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