1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Application\UI;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
23: abstract class Component extends Nette\ComponentModel\Container implements ISignalReceiver, IStatePersistent, \ArrayAccess
24: {
25:
26: public $onAnchor;
27:
28:
29: protected $params = [];
30:
31:
32: 33: 34: 35: 36:
37: public function getPresenter($throw = TRUE)
38: {
39: return $this->lookup(Presenter::class, $throw);
40: }
41:
42:
43: 44: 45: 46: 47:
48: public function getUniqueId()
49: {
50: return $this->lookupPath(Presenter::class, TRUE);
51: }
52:
53:
54: 55: 56: 57: 58: 59:
60: protected function attached($presenter)
61: {
62: if ($presenter instanceof Presenter) {
63: $this->loadState($presenter->popGlobalParameters($this->getUniqueId()));
64: $this->onAnchor($this);
65: }
66: }
67:
68:
69: 70: 71:
72: protected function validateParent(Nette\ComponentModel\IContainer $parent)
73: {
74: parent::validateParent($parent);
75: $this->monitor(Presenter::class);
76: }
77:
78:
79: 80: 81: 82: 83: 84:
85: protected function tryCall($method, array $params)
86: {
87: $rc = $this->getReflection();
88: if ($rc->hasMethod($method)) {
89: $rm = $rc->getMethod($method);
90: if ($rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic()) {
91: $this->checkRequirements($rm);
92: $rm->invokeArgs($this, $rc->combineArgs($rm, $params));
93: return TRUE;
94: }
95: }
96: return FALSE;
97: }
98:
99:
100: 101: 102: 103:
104: public function checkRequirements($element)
105: {
106: }
107:
108:
109: 110: 111: 112:
113: public static function getReflection()
114: {
115: return new ComponentReflection(get_called_class());
116: }
117:
118:
119:
120:
121:
122: 123: 124: 125: 126:
127: public function loadState(array $params)
128: {
129: $reflection = $this->getReflection();
130: foreach ($reflection->getPersistentParams() as $name => $meta) {
131: if (isset($params[$name])) {
132: $type = gettype($meta['def']);
133: if (!$reflection->convertType($params[$name], $type)) {
134: throw new Nette\Application\BadRequestException(sprintf(
135: "Value passed to persistent parameter '%s' in %s must be %s, %s given.",
136: $name,
137: $this instanceof Presenter ? 'presenter ' . $this->getName() : "component '{$this->getUniqueId()}'",
138: $type === 'NULL' ? 'scalar' : $type,
139: is_object($params[$name]) ? get_class($params[$name]) : gettype($params[$name])
140: ));
141: }
142: $this->$name = $params[$name];
143: } else {
144: $params[$name] = $this->$name;
145: }
146: }
147: $this->params = $params;
148: }
149:
150:
151: 152: 153: 154: 155: 156:
157: public function saveState(array &$params, $reflection = NULL)
158: {
159: $reflection = $reflection === NULL ? $this->getReflection() : $reflection;
160: foreach ($reflection->getPersistentParams() as $name => $meta) {
161:
162: if (isset($params[$name])) {
163:
164:
165: } elseif (array_key_exists($name, $params)) {
166: continue;
167:
168: } elseif ((!isset($meta['since']) || $this instanceof $meta['since']) && isset($this->$name)) {
169: $params[$name] = $this->$name;
170:
171: } else {
172: continue;
173: }
174:
175: $type = gettype($meta['def']);
176: if (!ComponentReflection::convertType($params[$name], $type)) {
177: throw new InvalidLinkException(sprintf(
178: "Value passed to persistent parameter '%s' in %s must be %s, %s given.",
179: $name,
180: $this instanceof Presenter ? 'presenter ' . $this->getName() : "component '{$this->getUniqueId()}'",
181: $type === 'NULL' ? 'scalar' : $type,
182: is_object($params[$name]) ? get_class($params[$name]) : gettype($params[$name])
183: ));
184: }
185:
186: if ($params[$name] === $meta['def'] || ($meta['def'] === NULL && $params[$name] === '')) {
187: $params[$name] = NULL;
188: }
189: }
190: }
191:
192:
193: 194: 195: 196: 197: 198:
199: public function getParameter($name, $default = NULL)
200: {
201: if (isset($this->params[$name])) {
202: return $this->params[$name];
203:
204: } else {
205: return $default;
206: }
207: }
208:
209:
210: 211: 212: 213:
214: public function getParameters()
215: {
216: return $this->params;
217: }
218:
219:
220: 221: 222: 223: 224:
225: public function getParameterId($name)
226: {
227: $uid = $this->getUniqueId();
228: return $uid === '' ? $name : $uid . self::NAME_SEPARATOR . $name;
229: }
230:
231:
232:
233: function getParam($name = NULL, $default = NULL)
234: {
235:
236: return func_num_args() ? $this->getParameter($name, $default) : $this->getParameters();
237: }
238:
239:
240: 241: 242: 243: 244:
245: public static function getPersistentParams()
246: {
247: $rc = new \ReflectionClass(get_called_class());
248: $params = [];
249: foreach ($rc->getProperties(\ReflectionProperty::IS_PUBLIC) as $rp) {
250: if (!$rp->isStatic() && ComponentReflection::parseAnnotation($rp, 'persistent')) {
251: $params[] = $rp->getName();
252: }
253: }
254: return $params;
255: }
256:
257:
258:
259:
260:
261: 262: 263: 264: 265: 266:
267: public function signalReceived($signal)
268: {
269: if (!$this->tryCall($this->formatSignalMethod($signal), $this->params)) {
270: $class = get_class($this);
271: throw new BadSignalException("There is no handler for signal '$signal' in class $class.");
272: }
273: }
274:
275:
276: 277: 278: 279: 280:
281: public static function formatSignalMethod($signal)
282: {
283: return $signal == NULL ? NULL : 'handle' . $signal;
284: }
285:
286:
287:
288:
289:
290: 291: 292: 293: 294: 295: 296:
297: public function link($destination, $args = [])
298: {
299: try {
300: $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1);
301: return $this->getPresenter()->createRequest($this, $destination, $args, 'link');
302:
303: } catch (InvalidLinkException $e) {
304: return $this->getPresenter()->handleInvalidLink($e);
305: }
306: }
307:
308:
309: 310: 311: 312: 313: 314:
315: public function lazyLink($destination, $args = [])
316: {
317: $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1);
318: return new Link($this, $destination, $args);
319: }
320:
321:
322: 323: 324: 325: 326: 327: 328:
329: public function isLinkCurrent($destination = NULL, $args = [])
330: {
331: if ($destination !== NULL) {
332: $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1);
333: $this->getPresenter()->createRequest($this, $destination, $args, 'test');
334: }
335: return $this->getPresenter()->getLastCreatedRequestFlag('current');
336: }
337:
338:
339: 340: 341: 342: 343: 344: 345: 346:
347: public function redirect($code, $destination = NULL, $args = [])
348: {
349: if (!is_numeric($code)) {
350: $args = func_num_args() < 3 && is_array($destination) ? $destination : array_slice(func_get_args(), 1);
351: $destination = $code;
352: $code = NULL;
353:
354: } elseif (func_num_args() > 3 || !is_array($args)) {
355: $args = array_slice(func_get_args(), 2);
356: }
357:
358: $presenter = $this->getPresenter();
359: $presenter->redirectUrl($presenter->createRequest($this, $destination, $args, 'redirect'), $code);
360: }
361:
362:
363: 364: 365: 366: 367: 368: 369:
370: public function redirectPermanent($destination = NULL, $args = [])
371: {
372: $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1);
373: $presenter = $this->getPresenter();
374: $presenter->redirectUrl(
375: $presenter->createRequest($this, $destination, $args, 'redirect'),
376: Nette\Http\IResponse::S301_MOVED_PERMANENTLY
377: );
378: }
379:
380:
381:
382:
383:
384: 385: 386: 387: 388: 389:
390: public function offsetSet($name, $component)
391: {
392: $this->addComponent($component, $name);
393: }
394:
395:
396: 397: 398: 399: 400: 401:
402: public function offsetGet($name)
403: {
404: return $this->getComponent($name, TRUE);
405: }
406:
407:
408: 409: 410: 411: 412:
413: public function offsetExists($name)
414: {
415: return $this->getComponent($name, FALSE) !== NULL;
416: }
417:
418:
419: 420: 421: 422: 423:
424: public function offsetUnset($name)
425: {
426: $component = $this->getComponent($name, FALSE);
427: if ($component !== NULL) {
428: $this->removeComponent($component);
429: }
430: }
431:
432: }
433: