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