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