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