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

  • Component
  • ComponentReflection
  • Control
  • Form
  • Link
  • MethodReflection
  • Multiplier
  • Presenter

Interfaces

  • IRenderable
  • ISignalReceiver
  • IStatePersistent
  • ITemplate
  • ITemplateFactory

Exceptions

  • BadSignalException
  • InvalidLinkException
  • 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\Application\UI;
  9: 
 10: use Nette;
 11: use Nette\Application\BadRequestException;
 12: use Nette\Reflection\ClassType;
 13: 
 14: 
 15: /**
 16:  * Helpers for Presenter & Component.
 17:  * @property-read string $name
 18:  * @property-read string $fileName
 19:  * @internal
 20:  */
 21: class ComponentReflection extends \ReflectionClass
 22: {
 23:     use Nette\SmartObject;
 24: 
 25:     /** @var array getPersistentParams cache */
 26:     private static $ppCache = [];
 27: 
 28:     /** @var array getPersistentComponents cache */
 29:     private static $pcCache = [];
 30: 
 31:     /** @var array isMethodCallable cache */
 32:     private static $mcCache = [];
 33: 
 34: 
 35:     /**
 36:      * @param  string|null
 37:      * @return array of persistent parameters.
 38:      */
 39:     public function getPersistentParams($class = null)
 40:     {
 41:         $class = $class === null ? $this->getName() : $class;
 42:         $params = &self::$ppCache[$class];
 43:         if ($params !== null) {
 44:             return $params;
 45:         }
 46:         $params = [];
 47:         if (is_subclass_of($class, Component::class)) {
 48:             $isPresenter = is_subclass_of($class, Presenter::class);
 49:             $defaults = get_class_vars($class);
 50:             foreach ($class::getPersistentParams() as $name => $default) {
 51:                 if (is_int($name)) {
 52:                     $name = $default;
 53:                     $default = $defaults[$name];
 54:                 }
 55:                 $params[$name] = [
 56:                     'def' => $default,
 57:                     'since' => $isPresenter ? $class : null,
 58:                 ];
 59:             }
 60:             foreach ($this->getPersistentParams(get_parent_class($class)) as $name => $param) {
 61:                 if (isset($params[$name])) {
 62:                     $params[$name]['since'] = $param['since'];
 63:                     continue;
 64:                 }
 65: 
 66:                 $params[$name] = $param;
 67:             }
 68:         }
 69:         return $params;
 70:     }
 71: 
 72: 
 73:     /**
 74:      * @param  string|null
 75:      * @return array of persistent components.
 76:      */
 77:     public function getPersistentComponents($class = null)
 78:     {
 79:         $class = $class === null ? $this->getName() : $class;
 80:         $components = &self::$pcCache[$class];
 81:         if ($components !== null) {
 82:             return $components;
 83:         }
 84:         $components = [];
 85:         if (is_subclass_of($class, Presenter::class)) {
 86:             foreach ($class::getPersistentComponents() as $name => $meta) {
 87:                 if (is_string($meta)) {
 88:                     $name = $meta;
 89:                 }
 90:                 $components[$name] = ['since' => $class];
 91:             }
 92:             $components = $this->getPersistentComponents(get_parent_class($class)) + $components;
 93:         }
 94:         return $components;
 95:     }
 96: 
 97: 
 98:     /**
 99:      * Saves state informations for next request.
100:      */
101:     public function saveState(Component $component, array &$params)
102:     {
103:         foreach ($this->getPersistentParams() as $name => $meta) {
104:             if (isset($params[$name])) {
105:                 // injected value
106: 
107:             } elseif (
108:                 array_key_exists($name, $params) // nulls are skipped
109:                 || (isset($meta['since']) && !$component instanceof $meta['since']) // not related
110:                 || !isset($component->$name)
111:             ) {
112:                 continue;
113: 
114:             } else {
115:                 $params[$name] = $component->$name; // object property value
116:             }
117: 
118:             $type = gettype($meta['def']);
119:             if (!self::convertType($params[$name], $type)) {
120:                 throw new InvalidLinkException(sprintf(
121:                     "Value passed to persistent parameter '%s' in %s must be %s, %s given.",
122:                     $name,
123:                     $component instanceof Presenter ? 'presenter ' . $component->getName() : "component '{$component->getUniqueId()}'",
124:                     $type === 'NULL' ? 'scalar' : $type,
125:                     is_object($params[$name]) ? get_class($params[$name]) : gettype($params[$name])
126:                 ));
127:             }
128: 
129:             if ($params[$name] === $meta['def'] || ($meta['def'] === null && $params[$name] === '')) {
130:                 $params[$name] = null; // value transmit is unnecessary
131:             }
132:         }
133:     }
134: 
135: 
136:     /**
137:      * Is a method callable? It means class is instantiable and method has
138:      * public visibility, is non-static and non-abstract.
139:      * @param  string  method name
140:      * @return bool
141:      */
142:     public function hasCallableMethod($method)
143:     {
144:         $class = $this->getName();
145:         $cache = &self::$mcCache[strtolower($class . ':' . $method)];
146:         if ($cache === null) {
147:             try {
148:                 $cache = false;
149:                 $rm = new \ReflectionMethod($class, $method);
150:                 $cache = $this->isInstantiable() && $rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic();
151:             } catch (\ReflectionException $e) {
152:             }
153:         }
154:         return $cache;
155:     }
156: 
157: 
158:     /**
159:      * @return array
160:      */
161:     public static function combineArgs(\ReflectionFunctionAbstract $method, $args)
162:     {
163:         $res = [];
164:         foreach ($method->getParameters() as $i => $param) {
165:             $name = $param->getName();
166:             list($type, $isClass) = self::getParameterType($param);
167:             if (isset($args[$name])) {
168:                 $res[$i] = $args[$name];
169:                 if (!self::convertType($res[$i], $type, $isClass)) {
170:                     throw new BadRequestException(sprintf(
171:                         'Argument $%s passed to %s() must be %s, %s given.',
172:                         $name,
173:                         ($method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' : '') . $method->getName(),
174:                         $type === 'NULL' ? 'scalar' : $type,
175:                         is_object($args[$name]) ? get_class($args[$name]) : gettype($args[$name])
176:                     ));
177:                 }
178:             } elseif ($param->isDefaultValueAvailable()) {
179:                 $res[$i] = $param->getDefaultValue();
180:             } elseif ($type === 'NULL' || $param->allowsNull()) {
181:                 $res[$i] = null;
182:             } elseif ($type === 'array') {
183:                 $res[$i] = [];
184:             } else {
185:                 throw new BadRequestException(sprintf(
186:                     'Missing parameter $%s required by %s()',
187:                     $name,
188:                     ($method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' : '') . $method->getName()
189:                 ));
190:             }
191:         }
192:         return $res;
193:     }
194: 
195: 
196:     /**
197:      * Non data-loss type conversion.
198:      * @param  mixed
199:      * @param  string
200:      * @return bool
201:      */
202:     public static function convertType(&$val, $type, $isClass = false)
203:     {
204:         if ($isClass) {
205:             return $val instanceof $type;
206: 
207:         } elseif ($type === 'callable') {
208:             return false;
209: 
210:         } elseif ($type === 'NULL') { // means 'not array'
211:             return !is_array($val);
212: 
213:         } elseif ($type === 'array') {
214:             return is_array($val);
215: 
216:         } elseif (!is_scalar($val)) { // array, resource, null, etc.
217:             return false;
218: 
219:         } else {
220:             $old = $tmp = ($val === false ? '0' : (string) $val);
221:             settype($tmp, $type);
222:             if ($old !== ($tmp === false ? '0' : (string) $tmp)) {
223:                 return false; // data-loss occurs
224:             }
225:             $val = $tmp;
226:         }
227:         return true;
228:     }
229: 
230: 
231:     /**
232:      * Returns an annotation value.
233:      * @return array|false
234:      */
235:     public static function parseAnnotation(\Reflector $ref, $name)
236:     {
237:         if (!preg_match_all('#[\\s*]@' . preg_quote($name, '#') . '(?:\(\\s*([^)]*)\\s*\)|\\s|$)#', $ref->getDocComment(), $m)) {
238:             return false;
239:         }
240:         static $tokens = ['true' => true, 'false' => false, 'null' => null];
241:         $res = [];
242:         foreach ($m[1] as $s) {
243:             foreach (preg_split('#\s*,\s*#', $s, -1, PREG_SPLIT_NO_EMPTY) ?: ['true'] as $item) {
244:                 $res[] = array_key_exists($tmp = strtolower($item), $tokens) ? $tokens[$tmp] : $item;
245:             }
246:         }
247:         return $res;
248:     }
249: 
250: 
251:     /**
252:      * @return array [string|null, bool]
253:      */
254:     public static function getParameterType(\ReflectionParameter $param)
255:     {
256:         $def = gettype($param->isDefaultValueAvailable() ? $param->getDefaultValue() : null);
257:         if (PHP_VERSION_ID >= 70000) {
258:             return $param->hasType()
259:                 ? [PHP_VERSION_ID >= 70100 ? $param->getType()->getName() : (string) $param->getType(), !$param->getType()->isBuiltin()]
260:                 : [$def, false];
261:         } elseif ($param->isArray() || $param->isCallable()) {
262:             return [$param->isArray() ? 'array' : 'callable', false];
263:         } else {
264:             try {
265:                 return ($ref = $param->getClass()) ? [$ref->getName(), true] : [$def, false];
266:             } catch (\ReflectionException $e) {
267:                 if (preg_match('#Class (.+) does not exist#', $e->getMessage(), $m)) {
268:                     throw new \LogicException(sprintf(
269:                         "Class %s not found. Check type hint of parameter $%s in %s() or 'use' statements.",
270:                         $m[1],
271:                         $param->getName(),
272:                         $param->getDeclaringFunction()->getDeclaringClass()->getName() . '::' . $param->getDeclaringFunction()->getName()
273:                     ));
274:                 }
275:                 throw $e;
276:             }
277:         }
278:     }
279: 
280: 
281:     /********************* compatiblity with Nette\Reflection ****************d*g**/
282: 
283: 
284:     /**
285:      * Has class specified annotation?
286:      * @param  string
287:      * @return bool
288:      */
289:     public function hasAnnotation($name)
290:     {
291:         return (bool) self::parseAnnotation($this, $name);
292:     }
293: 
294: 
295:     /**
296:      * Returns an annotation value.
297:      * @param  string
298:      * @return mixed
299:      */
300:     public function getAnnotation($name)
301:     {
302:         $res = self::parseAnnotation($this, $name);
303:         return $res ? end($res) : null;
304:     }
305: 
306: 
307:     /**
308:      * @return MethodReflection
309:      */
310:     public function getMethod($name)
311:     {
312:         return new MethodReflection($this->getName(), $name);
313:     }
314: 
315: 
316:     /**
317:      * @return MethodReflection[]
318:      */
319:     public function getMethods($filter = -1)
320:     {
321:         foreach ($res = parent::getMethods($filter) as $key => $val) {
322:             $res[$key] = new MethodReflection($this->getName(), $val->getName());
323:         }
324:         return $res;
325:     }
326: 
327: 
328:     public function __toString()
329:     {
330:         trigger_error(__METHOD__ . ' is deprecated.', E_USER_DEPRECATED);
331:         return $this->getName();
332:     }
333: 
334: 
335:     public function __get($name)
336:     {
337:         trigger_error("getReflection()->$name is deprecated.", E_USER_DEPRECATED);
338:         return (new ClassType($this->getName()))->$name;
339:     }
340: 
341: 
342:     public function __call($name, $args)
343:     {
344:         if (method_exists(ClassType::class, $name)) {
345:             trigger_error("getReflection()->$name() is deprecated, use Nette\\Reflection\\ClassType::from(\$presenter)->$name()", E_USER_DEPRECATED);
346:             return call_user_func_array([new ClassType($this->getName()), $name], $args);
347:         }
348:         Nette\Utils\ObjectMixin::strictCall(get_class($this), $name);
349:     }
350: }
351: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0