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:
28: abstract class NPresenter extends NControl implements IPresenter
29: {
30:
31: const INVALID_LINK_SILENT = 1;
32: const INVALID_LINK_WARNING = 2;
33: const INVALID_LINK_EXCEPTION = 3;
34:
35:
36:
37: const SIGNAL_KEY = 'do';
38: const ACTION_KEY = 'action';
39: const FLASH_KEY = '_fid';
40:
41:
42:
43: public static $defaultAction = 'default';
44:
45:
46: public static $invalidLinkMode;
47:
48:
49: public $onShutdown;
50:
51:
52: private $request;
53:
54:
55: private $response;
56:
57:
58: public $autoCanonicalize = TRUE;
59:
60:
61: public $absoluteUrls = FALSE;
62:
63:
64: private $globalParams;
65:
66:
67: private $globalState;
68:
69:
70: private $globalStateSinces;
71:
72:
73: private $action;
74:
75:
76: private $view;
77:
78:
79: private $layout;
80:
81:
82: private $payload;
83:
84:
85: private $signalReceiver;
86:
87:
88: private $signal;
89:
90:
91: private $ajaxMode;
92:
93:
94: private $startupCheck;
95:
96:
97: private $lastCreatedRequest;
98:
99:
100: private $lastCreatedRequestFlag;
101:
102:
103:
104: 105: 106:
107: final public function getRequest()
108: {
109: return $this->request;
110: }
111:
112:
113:
114: 115: 116: 117:
118: final public function getPresenter($need = TRUE)
119: {
120: return $this;
121: }
122:
123:
124:
125: 126: 127: 128:
129: final public function getUniqueId()
130: {
131: return '';
132: }
133:
134:
135:
136:
137:
138:
139:
140: 141: 142: 143:
144: public function run(NPresenterRequest $request)
145: {
146: try {
147: 148: $this->request = $request;
149: $this->payload = (object) NULL;
150: $this->setParent($this->getParent(), $request->getPresenterName());
151:
152: $this->initGlobalParams();
153: $this->startup();
154: if (!$this->startupCheck) {
155: $class = $this->reflection->getMethod('startup')->getDeclaringClass()->getName();
156: throw new InvalidStateException("Method $class::startup() or its descendant doesn't call parent::startup().");
157: }
158: 159: $this->tryCall($this->formatActionMethod($this->getAction()), $this->params);
160:
161: if ($this->autoCanonicalize) {
162: $this->canonicalize();
163: }
164: if ($this->getHttpRequest()->isMethod('head')) {
165: $this->terminate();
166: }
167:
168: 169: 170: $this->processSignal();
171:
172: 173: $this->beforeRender();
174: 175: $this->tryCall($this->formatRenderMethod($this->getView()), $this->params);
176: $this->afterRender();
177:
178: 179: $this->saveGlobalState();
180: if ($this->isAjax()) {
181: $this->payload->state = $this->getGlobalState();
182: }
183:
184: 185: $this->sendTemplate();
186:
187: } catch (NAbortException $e) {
188: 189: } {
190:
191: if ($this->isAjax()) try {
192: $hasPayload = (array) $this->payload; unset($hasPayload['state']);
193: if ($this->response instanceof NRenderResponse && ($this->isControlInvalid() || $hasPayload)) { 194: NSnippetHelper::$outputAllowed = FALSE;
195: $this->response->send();
196: $this->sendPayload();
197:
198: } elseif (!$this->response && $hasPayload) { 199: $this->sendPayload();
200: }
201: } catch (NAbortException $e) { }
202:
203: if ($this->hasFlashSession()) {
204: $this->getFlashSession()->setExpiration($this->response instanceof NRedirectingResponse ? '+ 30 seconds': '+ 3 seconds');
205: }
206:
207: 208: $this->onShutdown($this, $this->response);
209: $this->shutdown($this->response);
210:
211: return $this->response;
212: }
213: }
214:
215:
216:
217: 218: 219:
220: protected function startup()
221: {
222: $this->startupCheck = TRUE;
223: }
224:
225:
226:
227: 228: 229: 230:
231: protected function beforeRender()
232: {
233: }
234:
235:
236:
237: 238: 239: 240:
241: protected function afterRender()
242: {
243: }
244:
245:
246:
247: 248: 249: 250:
251: protected function shutdown($response)
252: {
253: }
254:
255:
256:
257:
258:
259:
260:
261: 262: 263: 264:
265: public function processSignal()
266: {
267: if ($this->signal === NULL) return;
268:
269: $component = $this->signalReceiver === '' ? $this : $this->getComponent($this->signalReceiver, FALSE);
270: if ($component === NULL) {
271: throw new NBadSignalException("The signal receiver component '$this->signalReceiver' is not found.");
272:
273: } elseif (!$component instanceof ISignalReceiver) {
274: throw new NBadSignalException("The signal receiver component '$this->signalReceiver' is not ISignalReceiver implementor.");
275: }
276:
277: $component->signalReceived($this->signal);
278: $this->signal = NULL;
279: }
280:
281:
282:
283: 284: 285: 286:
287: final public function getSignal()
288: {
289: return $this->signal === NULL ? NULL : array($this->signalReceiver, $this->signal);
290: }
291:
292:
293:
294: 295: 296: 297: 298: 299:
300: final public function isSignalReceiver($component, $signal = NULL)
301: {
302: if ($component instanceof NComponent) {
303: $component = $component === $this ? '' : $component->lookupPath(__CLASS__, TRUE);
304: }
305:
306: if ($this->signal === NULL) {
307: return FALSE;
308:
309: } elseif ($signal === TRUE) {
310: return $component === ''
311: || strncmp($this->signalReceiver . '-', $component . '-', strlen($component) + 1) === 0;
312:
313: } elseif ($signal === NULL) {
314: return $this->signalReceiver === $component;
315:
316: } else {
317: return $this->signalReceiver === $component && strcasecmp($signal, $this->signal) === 0;
318: }
319: }
320:
321:
322:
323:
324:
325:
326:
327: 328: 329: 330:
331: final public function getAction($fullyQualified = FALSE)
332: {
333: return $fullyQualified ? ':' . $this->getName() . ':' . $this->action : $this->action;
334: }
335:
336:
337:
338: 339: 340: 341: 342:
343: public function changeAction($action)
344: {
345: if (NString::match($action, "#^[a-zA-Z0-9][a-zA-Z0-9_\x7f-\xff]*$#")) {
346: $this->action = $action;
347: $this->view = $action;
348:
349: } else {
350: throw new NBadRequestException("Action name '$action' is not alphanumeric string.");
351: }
352: }
353:
354:
355:
356: 357: 358: 359:
360: final public function getView()
361: {
362: return $this->view;
363: }
364:
365:
366:
367: 368: 369: 370: 371:
372: public function setView($view)
373: {
374: $this->view = (string) $view;
375: return $this;
376: }
377:
378:
379:
380: 381: 382: 383:
384: final public function getLayout()
385: {
386: return $this->layout;
387: }
388:
389:
390:
391: 392: 393: 394: 395:
396: public function setLayout($layout)
397: {
398: $this->layout = $layout === FALSE ? FALSE : (string) $layout;
399: return $this;
400: }
401:
402:
403:
404: 405: 406: 407: 408:
409: public function sendTemplate()
410: {
411: $template = $this->getTemplate();
412: if (!$template) return;
413:
414: if ($template instanceof IFileTemplate && !$template->getFile()) {
415:
416: 417: $files = $this->formatTemplateFiles($this->getName(), $this->view);
418: foreach ($files as $file) {
419: if (is_file($file)) {
420: $template->setFile($file);
421: break;
422: }
423: }
424:
425: if (!$template->getFile()) {
426: $file = str_replace(NEnvironment::getVariable('appDir'), "\xE2\x80\xA6", reset($files));
427: throw new NBadRequestException("Page not found. Missing template '$file'.");
428: }
429:
430: 431: if ($this->layout !== FALSE) {
432: $files = $this->formatLayoutTemplateFiles($this->getName(), $this->layout ? $this->layout : 'layout');
433: foreach ($files as $file) {
434: if (is_file($file)) {
435: $template->layout = $file;
436: $template->_extends = $file;
437: break;
438: }
439: }
440:
441: if (empty($template->layout) && $this->layout !== NULL) {
442: $file = str_replace(NEnvironment::getVariable('appDir'), "\xE2\x80\xA6", reset($files));
443: throw new FileNotFoundException("Layout not found. Missing template '$file'.");
444: }
445: }
446: }
447:
448: $this->sendResponse(new NRenderResponse($template));
449: }
450:
451:
452:
453: 454: 455: 456: 457: 458:
459: public function formatLayoutTemplateFiles($presenter, $layout)
460: {
461: $appDir = NEnvironment::getVariable('appDir');
462: $path = '/' . str_replace(':', 'Module/', $presenter);
463: $pathP = substr_replace($path, '/templates', strrpos($path, '/'), 0);
464: $list = array(
465: "$appDir$pathP/@$layout.phtml",
466: "$appDir$pathP.@$layout.phtml",
467: );
468: while (($path = substr($path, 0, strrpos($path, '/'))) !== FALSE) {
469: $list[] = "$appDir$path/templates/@$layout.phtml";
470: }
471: return $list;
472: }
473:
474:
475:
476: 477: 478: 479: 480: 481:
482: public function formatTemplateFiles($presenter, $view)
483: {
484: $appDir = NEnvironment::getVariable('appDir');
485: $path = '/' . str_replace(':', 'Module/', $presenter);
486: $pathP = substr_replace($path, '/templates', strrpos($path, '/'), 0);
487: $path = substr_replace($path, '/templates', strrpos($path, '/'));
488: return array(
489: "$appDir$pathP/$view.phtml",
490: "$appDir$pathP.$view.phtml",
491: "$appDir$path/@global.$view.phtml",
492: );
493: }
494:
495:
496:
497: 498: 499: 500: 501:
502: protected static function formatActionMethod($action)
503: {
504: return 'action' . $action;
505: }
506:
507:
508:
509: 510: 511: 512: 513:
514: protected static function formatRenderMethod($view)
515: {
516: return 'render' . $view;
517: }
518:
519:
520:
521:
522:
523:
524:
525: 526: 527:
528: final public function getPayload()
529: {
530: return $this->payload;
531: }
532:
533:
534:
535: 536: 537: 538:
539: public function isAjax()
540: {
541: if ($this->ajaxMode === NULL) {
542: $this->ajaxMode = $this->getHttpRequest()->isAjax();
543: }
544: return $this->ajaxMode;
545: }
546:
547:
548:
549: 550: 551: 552: 553:
554: public function sendPayload()
555: {
556: $this->sendResponse(new NJsonResponse($this->payload));
557: }
558:
559:
560:
561:
562:
563:
564:
565: 566: 567: 568: 569: 570:
571: public function sendResponse(IPresenterResponse $response)
572: {
573: $this->response = $response;
574: $this->terminate();
575: }
576:
577:
578:
579: 580: 581: 582: 583:
584: public function terminate()
585: {
586: if (func_num_args() !== 0) {
587: trigger_error(__METHOD__ . ' is not intended to send a PresenterResponse; use sendResponse() instead.', E_USER_WARNING);
588: $this->sendResponse(func_get_arg(0));
589: }
590: throw new NAbortException();
591: }
592:
593:
594:
595: 596: 597: 598: 599: 600: 601:
602: public function forward($destination, $args = array())
603: {
604: if ($destination instanceof NPresenterRequest) {
605: $this->sendResponse(new NForwardingResponse($destination));
606:
607: } elseif (!is_array($args)) {
608: $args = func_get_args();
609: array_shift($args);
610: }
611:
612: $this->createRequest($this, $destination, $args, 'forward');
613: $this->sendResponse(new NForwardingResponse($this->lastCreatedRequest));
614: }
615:
616:
617:
618: 619: 620: 621: 622: 623: 624:
625: public function redirectUri($uri, $code = NULL)
626: {
627: if ($this->isAjax()) {
628: $this->payload->redirect = (string) $uri;
629: $this->sendPayload();
630:
631: } elseif (!$code) {
632: $code = $this->getHttpRequest()->isMethod('post') ? IHttpResponse::S303_POST_GET : IHttpResponse::S302_FOUND;
633: }
634: $this->sendResponse(new NRedirectingResponse($uri, $code));
635: }
636:
637:
638:
639: 640: 641: 642:
643: public function backlink()
644: {
645: return $this->getAction(TRUE);
646: }
647:
648:
649:
650: 651: 652: 653:
654: public function getLastCreatedRequest()
655: {
656: return $this->lastCreatedRequest;
657: }
658:
659:
660:
661: 662: 663: 664: 665:
666: public function getLastCreatedRequestFlag($flag)
667: {
668: return !empty($this->lastCreatedRequestFlag[$flag]);
669: }
670:
671:
672:
673: 674: 675: 676: 677:
678: public function canonicalize()
679: {
680: if (!$this->isAjax() && ($this->request->isMethod('get') || $this->request->isMethod('head'))) {
681: $uri = $this->createRequest($this, $this->action, $this->getGlobalState() + $this->request->params, 'redirectX');
682: if ($uri !== NULL && !$this->getHttpRequest()->getUri()->isEqual($uri)) {
683: $this->sendResponse(new NRedirectingResponse($uri, IHttpResponse::S301_MOVED_PERMANENTLY));
684: }
685: }
686: }
687:
688:
689:
690: 691: 692: 693: 694: 695: 696: 697: 698:
699: public function lastModified($lastModified, $etag = NULL, $expire = NULL)
700: {
701: if (!NEnvironment::isProduction()) {
702: return;
703: }
704:
705: if ($expire !== NULL) {
706: $this->getHttpResponse()->setExpiration($expire);
707: }
708:
709: if (!$this->getHttpContext()->isModified($lastModified, $etag)) {
710: $this->terminate();
711: }
712: }
713:
714:
715:
716: 717: 718: 719: 720: 721: 722: 723: 724: 725:
726: final protected function createRequest($component, $destination, array $args, $mode)
727: {
728: 729:
730: 731: static $presenterLoader, $router, $httpRequest;
732: if ($presenterLoader === NULL) {
733: $presenterLoader = $this->getApplication()->getPresenterLoader();
734: $router = $this->getApplication()->getRouter();
735: $httpRequest = $this->getHttpRequest();
736: }
737:
738: $this->lastCreatedRequest = $this->lastCreatedRequestFlag = NULL;
739:
740: 741: 742: $a = strpos($destination, '#');
743: if ($a === FALSE) {
744: $fragment = '';
745: } else {
746: $fragment = substr($destination, $a);
747: $destination = substr($destination, 0, $a);
748: }
749:
750: 751: $a = strpos($destination, '?');
752: if ($a !== FALSE) {
753: parse_str(substr($destination, $a + 1), $args); 754: $destination = substr($destination, 0, $a);
755: }
756:
757: 758: $a = strpos($destination, '//');
759: if ($a === FALSE) {
760: $scheme = FALSE;
761: } else {
762: $scheme = substr($destination, 0, $a);
763: $destination = substr($destination, $a + 2);
764: }
765:
766: 767: if (!($component instanceof NPresenter) || substr($destination, -1) === '!') {
768: $signal = rtrim($destination, '!');
769: $a = strrpos($signal, ':');
770: if ($a !== FALSE) {
771: $component = $component->getComponent(strtr(substr($signal, 0, $a), ':', '-'));
772: $signal = (string) substr($signal, $a + 1);
773: }
774: if ($signal == NULL) { 775: throw new NInvalidLinkException("Signal must be non-empty string.");
776: }
777: $destination = 'this';
778: }
779:
780: if ($destination == NULL) { 781: throw new NInvalidLinkException("Destination must be non-empty string.");
782: }
783:
784: 785: $current = FALSE;
786: $a = strrpos($destination, ':');
787: if ($a === FALSE) {
788: $action = $destination === 'this' ? $this->action : $destination;
789: $presenter = $this->getName();
790: $presenterClass = get_class($this);
791:
792: } else {
793: $action = (string) substr($destination, $a + 1);
794: if ($destination[0] === ':') { 795: if ($a < 2) {
796: throw new NInvalidLinkException("Missing presenter name in '$destination'.");
797: }
798: $presenter = substr($destination, 1, $a - 1);
799:
800: } else { 801: $presenter = $this->getName();
802: $b = strrpos($presenter, ':');
803: if ($b === FALSE) { 804: $presenter = substr($destination, 0, $a);
805: } else { 806: $presenter = substr($presenter, 0, $b + 1) . substr($destination, 0, $a);
807: }
808: }
809: $presenterClass = $presenterLoader->getPresenterClass($presenter);
810: }
811:
812: 813: if (isset($signal)) { 814: $reflection = new NPresenterComponentReflection(get_class($component));
815: if ($signal === 'this') { 816: $signal = '';
817: if (array_key_exists(0, $args)) {
818: throw new NInvalidLinkException("Unable to pass parameters to 'this!' signal.");
819: }
820:
821: } elseif (strpos($signal, self::NAME_SEPARATOR) === FALSE) { 822: 823: $method = $component->formatSignalMethod($signal);
824: if (!$reflection->hasCallableMethod($method)) {
825: throw new NInvalidLinkException("Unknown signal '$signal', missing handler {$reflection->name}::$method()");
826: }
827: if ($args) { 828: self::argsToParams(get_class($component), $method, $args);
829: }
830: }
831:
832: 833: if ($args && array_intersect_key($args, $reflection->getPersistentParams())) {
834: $component->saveState($args);
835: }
836:
837: if ($args && $component !== $this) {
838: $prefix = $component->getUniqueId() . self::NAME_SEPARATOR;
839: foreach ($args as $key => $val) {
840: unset($args[$key]);
841: $args[$prefix . $key] = $val;
842: }
843: }
844: }
845:
846: 847: if (is_subclass_of($presenterClass, __CLASS__)) {
848: if ($action === '') {
849: $action = self::$defaultAction;
850: }
851:
852: $current = ($action === '*' || $action === $this->action) && $presenterClass === get_class($this); 853:
854: $reflection = new NPresenterComponentReflection($presenterClass);
855: if ($args || $destination === 'this') {
856: 857: $method = call_user_func(array($presenterClass, 'formatActionMethod'), $action);
858: if (!$reflection->hasCallableMethod($method)) {
859: $method = call_user_func(array($presenterClass, 'formatRenderMethod'), $action);
860: if (!$reflection->hasCallableMethod($method)) {
861: $method = NULL;
862: }
863: }
864:
865: 866: if ($method === NULL) {
867: if (array_key_exists(0, $args)) {
868: throw new NInvalidLinkException("Unable to pass parameters to action '$presenter:$action', missing corresponding method.");
869: }
870:
871: } elseif ($destination === 'this') {
872: self::argsToParams($presenterClass, $method, $args, $this->params);
873:
874: } else {
875: self::argsToParams($presenterClass, $method, $args);
876: }
877: }
878:
879: 880: if ($args && array_intersect_key($args, $reflection->getPersistentParams())) {
881: $this->saveState($args, $reflection);
882: }
883:
884: $globalState = $this->getGlobalState($destination === 'this' ? NULL : $presenterClass);
885: if ($current && $args) {
886: $tmp = $globalState + $this->params;
887: foreach ($args as $key => $val) {
888: if ((string) $val !== (isset($tmp[$key]) ? (string) $tmp[$key] : '')) {
889: $current = FALSE;
890: break;
891: }
892: }
893: }
894: $args += $globalState;
895: }
896:
897: 898: $args[self::ACTION_KEY] = $action;
899: if (!empty($signal)) {
900: $args[self::SIGNAL_KEY] = $component->getParamId($signal);
901: $current = $current && $args[self::SIGNAL_KEY] === $this->getParam(self::SIGNAL_KEY);
902: }
903: if (($mode === 'redirect' || $mode === 'forward') && $this->hasFlashSession()) {
904: $args[self::FLASH_KEY] = $this->getParam(self::FLASH_KEY);
905: }
906:
907: $this->lastCreatedRequest = new NPresenterRequest(
908: $presenter,
909: NPresenterRequest::FORWARD,
910: $args,
911: array(),
912: array()
913: );
914: $this->lastCreatedRequestFlag = array('current' => $current);
915:
916: if ($mode === 'forward') return;
917:
918: 919: $uri = $router->constructUrl($this->lastCreatedRequest, $httpRequest);
920: if ($uri === NULL) {
921: unset($args[self::ACTION_KEY]);
922: $params = urldecode(http_build_query($args, NULL, ', '));
923: throw new NInvalidLinkException("No route for $presenter:$action($params)");
924: }
925:
926: 927: if ($mode === 'link' && $scheme === FALSE && !$this->absoluteUrls) {
928: $hostUri = $httpRequest->getUri()->getHostUri();
929: if (strncmp($uri, $hostUri, strlen($hostUri)) === 0) {
930: $uri = substr($uri, strlen($hostUri));
931: }
932: }
933:
934: return $uri . $fragment;
935: }
936:
937:
938:
939: 940: 941: 942: 943: 944: 945: 946: 947:
948: private static function argsToParams($class, $method, & $args, $supplemental = array())
949: {
950: static $cache;
951: $params = & $cache[strtolower($class . ':' . $method)];
952: if ($params === NULL) {
953: $params = NMethodReflection::from($class, $method)->getDefaultParameters();
954: }
955: $i = 0;
956: foreach ($params as $name => $def) {
957: if (array_key_exists($i, $args)) {
958: $args[$name] = $args[$i];
959: unset($args[$i]);
960: $i++;
961:
962: } elseif (array_key_exists($name, $args)) {
963: 964:
965: } elseif (array_key_exists($name, $supplemental)) {
966: $args[$name] = $supplemental[$name];
967:
968: } else {
969: continue;
970: }
971:
972: if ($def === NULL) {
973: if ((string) $args[$name] === '') $args[$name] = NULL; 974: } else {
975: settype($args[$name], gettype($def));
976: if ($args[$name] === $def) $args[$name] = NULL;
977: }
978: }
979:
980: if (array_key_exists($i, $args)) {
981: $method = NMethodReflection::from($class, $method)->getName();
982: throw new NInvalidLinkException("Passed more parameters than method $class::$method() expects.");
983: }
984: }
985:
986:
987:
988: 989: 990: 991: 992: 993:
994: protected function handleInvalidLink($e)
995: {
996: if (self::$invalidLinkMode === NULL) {
997: self::$invalidLinkMode = NEnvironment::isProduction()
998: ? self::INVALID_LINK_SILENT : self::INVALID_LINK_WARNING;
999: }
1000:
1001: if (self::$invalidLinkMode === self::INVALID_LINK_SILENT) {
1002: return '#';
1003:
1004: } elseif (self::$invalidLinkMode === self::INVALID_LINK_WARNING) {
1005: return 'error: ' . $e->getMessage();
1006:
1007: } else { 1008: throw $e;
1009: }
1010: }
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018: 1019: 1020: 1021: 1022:
1023: public static function getPersistentComponents()
1024: {
1025: return (array) NClassReflection::from(func_get_arg(0))->getAnnotation('persistent');
1026: }
1027:
1028:
1029:
1030: 1031: 1032: 1033:
1034: private function getGlobalState($forClass = NULL)
1035: {
1036: $sinces = & $this->globalStateSinces;
1037:
1038: if ($this->globalState === NULL) {
1039: $state = array();
1040: foreach ($this->globalParams as $id => $params) {
1041: $prefix = $id . self::NAME_SEPARATOR;
1042: foreach ($params as $key => $val) {
1043: $state[$prefix . $key] = $val;
1044: }
1045: }
1046: $this->saveState($state, $forClass ? new NPresenterComponentReflection($forClass) : NULL);
1047:
1048: if ($sinces === NULL) {
1049: $sinces = array();
1050: foreach ($this->getReflection()->getPersistentParams() as $nm => $meta) {
1051: $sinces[$nm] = $meta['since'];
1052: }
1053: }
1054:
1055: $components = $this->getReflection()->getPersistentComponents();
1056: $iterator = $this->getComponents(TRUE, 'IStatePersistent');
1057: foreach ($iterator as $name => $component)
1058: {
1059: if ($iterator->getDepth() === 0) {
1060: 1061: $since = isset($components[$name]['since']) ? $components[$name]['since'] : FALSE; 1062: }
1063: $prefix = $component->getUniqueId() . self::NAME_SEPARATOR;
1064: $params = array();
1065: $component->saveState($params);
1066: foreach ($params as $key => $val) {
1067: $state[$prefix . $key] = $val;
1068: $sinces[$prefix . $key] = $since;
1069: }
1070: }
1071:
1072: } else {
1073: $state = $this->globalState;
1074: }
1075:
1076: if ($forClass !== NULL) {
1077: $since = NULL;
1078: foreach ($state as $key => $foo) {
1079: if (!isset($sinces[$key])) {
1080: $x = strpos($key, self::NAME_SEPARATOR);
1081: $x = $x === FALSE ? $key : substr($key, 0, $x);
1082: $sinces[$key] = isset($sinces[$x]) ? $sinces[$x] : FALSE;
1083: }
1084: if ($since !== $sinces[$key]) {
1085: $since = $sinces[$key];
1086: $ok = $since && (is_subclass_of($forClass, $since) || $forClass === $since);
1087: }
1088: if (!$ok) {
1089: unset($state[$key]);
1090: }
1091: }
1092: }
1093:
1094: return $state;
1095: }
1096:
1097:
1098:
1099: 1100: 1101: 1102:
1103: protected function saveGlobalState()
1104: {
1105: 1106: foreach ($this->globalParams as $id => $foo) {
1107: $this->getComponent($id, FALSE);
1108: }
1109:
1110: $this->globalParams = array();
1111: $this->globalState = $this->getGlobalState();
1112: }
1113:
1114:
1115:
1116: 1117: 1118: 1119: 1120:
1121: private function initGlobalParams()
1122: {
1123: 1124: $this->globalParams = array();
1125: $selfParams = array();
1126:
1127: $params = $this->request->getParams();
1128: if ($this->isAjax()) {
1129: $params = $this->request->getPost() + $params;
1130: }
1131:
1132: foreach ($params as $key => $value) {
1133: $a = strlen($key) > 2 ? strrpos($key, self::NAME_SEPARATOR, -2) : FALSE;
1134: if ($a === FALSE) {
1135: $selfParams[$key] = $value;
1136: } else {
1137: $this->globalParams[substr($key, 0, $a)][substr($key, $a + 1)] = $value;
1138: }
1139: }
1140:
1141: 1142: $this->changeAction(isset($selfParams[self::ACTION_KEY]) ? $selfParams[self::ACTION_KEY] : self::$defaultAction);
1143:
1144: 1145: $this->signalReceiver = $this->getUniqueId();
1146: if (!empty($selfParams[self::SIGNAL_KEY])) {
1147: $param = $selfParams[self::SIGNAL_KEY];
1148: $pos = strrpos($param, '-');
1149: if ($pos) {
1150: $this->signalReceiver = substr($param, 0, $pos);
1151: $this->signal = substr($param, $pos + 1);
1152: } else {
1153: $this->signalReceiver = $this->getUniqueId();
1154: $this->signal = $param;
1155: }
1156: if ($this->signal == NULL) { 1157: $this->signal = NULL;
1158: }
1159: }
1160:
1161: $this->loadState($selfParams);
1162: }
1163:
1164:
1165:
1166: 1167: 1168: 1169: 1170:
1171: final public function popGlobalParams($id)
1172: {
1173: if (isset($this->globalParams[$id])) {
1174: $res = $this->globalParams[$id];
1175: unset($this->globalParams[$id]);
1176: return $res;
1177:
1178: } else {
1179: return array();
1180: }
1181: }
1182:
1183:
1184:
1185:
1186:
1187:
1188:
1189: 1190: 1191: 1192:
1193: public function hasFlashSession()
1194: {
1195: return !empty($this->params[self::FLASH_KEY])
1196: && $this->getSession()->hasNamespace('Nette.Application.Flash/' . $this->params[self::FLASH_KEY]);
1197: }
1198:
1199:
1200:
1201: 1202: 1203: 1204:
1205: public function getFlashSession()
1206: {
1207: if (empty($this->params[self::FLASH_KEY])) {
1208: $this->params[self::FLASH_KEY] = substr(md5(lcg_value()), 0, 4);
1209: }
1210: return $this->getSession('Nette.Application.Flash/' . $this->params[self::FLASH_KEY]);
1211: }
1212:
1213:
1214:
1215:
1216:
1217:
1218:
1219: 1220: 1221:
1222: protected function getHttpRequest()
1223: {
1224: return NEnvironment::getHttpRequest();
1225: }
1226:
1227:
1228:
1229: 1230: 1231:
1232: protected function getHttpResponse()
1233: {
1234: return NEnvironment::getHttpResponse();
1235: }
1236:
1237:
1238:
1239: 1240: 1241:
1242: protected function getHttpContext()
1243: {
1244: return NEnvironment::getHttpContext();
1245: }
1246:
1247:
1248:
1249: 1250: 1251:
1252: public function getApplication()
1253: {
1254: return NEnvironment::getApplication();
1255: }
1256:
1257:
1258:
1259: 1260: 1261:
1262: public function getSession($namespace = NULL)
1263: {
1264: return NEnvironment::getSession($namespace);
1265: }
1266:
1267:
1268:
1269: 1270: 1271:
1272: public function getUser()
1273: {
1274: return NEnvironment::getUser();
1275: }
1276:
1277: }
1278: