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: public function saveState(array &$params)
156: {
157: $this->getReflection()->saveState($this, $params);
158: }
159:
160:
161: 162: 163: 164: 165: 166:
167: public function getParameter($name, $default = null)
168: {
169: if (isset($this->params[$name])) {
170: return $this->params[$name];
171:
172: } else {
173: return $default;
174: }
175: }
176:
177:
178: 179: 180: 181:
182: public function getParameters()
183: {
184: return $this->params;
185: }
186:
187:
188: 189: 190: 191: 192:
193: public function getParameterId($name)
194: {
195: $uid = $this->getUniqueId();
196: return $uid === '' ? $name : $uid . self::NAME_SEPARATOR . $name;
197: }
198:
199:
200:
201: public function getParam($name = null, $default = null)
202: {
203:
204: return func_num_args() ? $this->getParameter($name, $default) : $this->getParameters();
205: }
206:
207:
208: 209: 210: 211: 212:
213: public static function getPersistentParams()
214: {
215: $rc = new \ReflectionClass(get_called_class());
216: $params = [];
217: foreach ($rc->getProperties(\ReflectionProperty::IS_PUBLIC) as $rp) {
218: if (!$rp->isStatic() && ComponentReflection::parseAnnotation($rp, 'persistent')) {
219: $params[] = $rp->getName();
220: }
221: }
222: return $params;
223: }
224:
225:
226:
227:
228:
229: 230: 231: 232: 233: 234:
235: public function signalReceived($signal)
236: {
237: if (!$this->tryCall($this->formatSignalMethod($signal), $this->params)) {
238: $class = get_class($this);
239: throw new BadSignalException("There is no handler for signal '$signal' in class $class.");
240: }
241: }
242:
243:
244: 245: 246: 247: 248:
249: public static function formatSignalMethod($signal)
250: {
251: return $signal == null ? null : 'handle' . $signal;
252: }
253:
254:
255:
256:
257:
258: 259: 260: 261: 262: 263: 264:
265: public function link($destination, $args = [])
266: {
267: try {
268: $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1);
269: return $this->getPresenter()->createRequest($this, $destination, $args, 'link');
270:
271: } catch (InvalidLinkException $e) {
272: return $this->getPresenter()->handleInvalidLink($e);
273: }
274: }
275:
276:
277: 278: 279: 280: 281: 282:
283: public function lazyLink($destination, $args = [])
284: {
285: $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1);
286: return new Link($this, $destination, $args);
287: }
288:
289:
290: 291: 292: 293: 294: 295: 296:
297: public function isLinkCurrent($destination = null, $args = [])
298: {
299: if ($destination !== null) {
300: $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1);
301: $this->getPresenter()->createRequest($this, $destination, $args, 'test');
302: }
303: return $this->getPresenter()->getLastCreatedRequestFlag('current');
304: }
305:
306:
307: 308: 309: 310: 311: 312: 313: 314:
315: public function redirect($code, $destination = null, $args = [])
316: {
317: if (!is_numeric($code)) {
318: $args = func_num_args() < 3 && is_array($destination) ? $destination : array_slice(func_get_args(), 1);
319: $destination = $code;
320: $code = null;
321:
322: } elseif (func_num_args() > 3 || !is_array($args)) {
323: $args = array_slice(func_get_args(), 2);
324: }
325:
326: $presenter = $this->getPresenter();
327: $presenter->redirectUrl($presenter->createRequest($this, $destination, $args, 'redirect'), $code);
328: }
329:
330:
331: 332: 333: 334: 335: 336: 337:
338: public function redirectPermanent($destination = null, $args = [])
339: {
340: $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1);
341: $presenter = $this->getPresenter();
342: $presenter->redirectUrl(
343: $presenter->createRequest($this, $destination, $args, 'redirect'),
344: Nette\Http\IResponse::S301_MOVED_PERMANENTLY
345: );
346: }
347:
348:
349: 350: 351: 352: 353: 354: 355:
356: public function error($message = null, $httpCode = Nette\Http\IResponse::S404_NOT_FOUND)
357: {
358: throw new Nette\Application\BadRequestException($message, $httpCode);
359: }
360:
361:
362:
363:
364:
365: 366: 367: 368: 369: 370:
371: public function offsetSet($name, $component)
372: {
373: $this->addComponent($component, $name);
374: }
375:
376:
377: 378: 379: 380: 381: 382:
383: public function offsetGet($name)
384: {
385: return $this->getComponent($name, true);
386: }
387:
388:
389: 390: 391: 392: 393:
394: public function offsetExists($name)
395: {
396: return $this->getComponent($name, false) !== null;
397: }
398:
399:
400: 401: 402: 403: 404:
405: public function offsetUnset($name)
406: {
407: $component = $this->getComponent($name, false);
408: if ($component !== null) {
409: $this->removeComponent($component);
410: }
411: }
412: }
413: