Source for file Presenter.php

Documentation is available at Presenter.php

  1. 1: <?php
  2. 2:  
  3. 3: /**
  4. 4:  * Nette Framework
  5. 5:  *
  6. 6:  * Copyright (c) 2004, 2009 David Grudl (http://davidgrudl.com)
  7. 7:  *
  8. 8:  * This source file is subject to the "Nette license" that is bundled
  9. 9:  * with this package in the file license.txt.
  10. 10:  *
  11. 11:  * For more information please see http://nettephp.com
  12. 12:  *
  13. 13:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  14. 14:  * @license    http://nettephp.com/license  Nette license
  15. 15:  * @link       http://nettephp.com
  16. 16:  * @category   Nette
  17. 17:  * @package    Application
  18. 18:  */
  19. 19:  
  20. 20:  
  21. 21:  
  22. 22: require_once dirname(__FILE__'/../Application/Control.php';
  23. 23:  
  24. 24: require_once dirname(__FILE__'/../Application/IPresenter.php';
  25. 25:  
  26. 26:  
  27. 27:  
  28. 28: /**
  29. 29:  * NPresenter object represents a webpage instance. It executes all the logic for the request.
  30. 30:  *
  31. 31:  * @author     David Grudl
  32. 32:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  33. 33:  * @package    Application
  34. 34:  *
  35. 35:  * @property-read NPresenterRequest $request 
  36. 36:  * @property-read int $phase 
  37. 37:  * @property-read array $signal 
  38. 38:  * @property-read string $action 
  39. 39:  * @property   string $view 
  40. 40:  * @property   string $layout 
  41. 41:  * @property-read mixed $payload 
  42. 42:  * @property-read NApplication $application 
  43. 43:  */
  44. 44: abstract class NPresenter extends NControl implements IPresenter
  45. 45: {
  46. 46:     /**#@+ life cycle phases {@link NPresenter::getPhase()} */
  47. 47:     const PHASE_STARTUP = 1;
  48. 48:     const PHASE_SIGNAL = 3;
  49. 49:     const PHASE_RENDER = 4;
  50. 50:     const PHASE_SHUTDOWN = 5;
  51. 51:     /**#@-*/
  52. 52:  
  53. 53:     /**#@+ bad link handling {@link NPresenter::$invalidLinkMode} */
  54. 54:     const INVALID_LINK_SILENT = 1;
  55. 55:     const INVALID_LINK_WARNING = 2;
  56. 56:     const INVALID_LINK_EXCEPTION = 3;
  57. 57:     /**#@-*/
  58. 58:  
  59. 59:     /**#@+ special parameter key */
  60. 60:     const SIGNAL_KEY = 'do';
  61. 61:     const ACTION_KEY = 'action';
  62. 62:     const FLASH_KEY = '_fid';
  63. 63:     /**#@-*/
  64. 64:  
  65. 65:     /** @var string */
  66. 66:     public static $defaultAction 'default';
  67. 67:  
  68. 68:     /** @var int */
  69. 69:     public static $invalidLinkMode;
  70. 70:  
  71. 71:     /** @var array of function(NPresenter $sender, IPresenterResponse $response = NULL); Occurs when the presenter is shutting down */
  72. 72:     public $onShutdown;
  73. 73:  
  74. 74:     /** @var bool (experimental) */
  75. 75:     public $oldLayoutMode = TRUE;
  76. 76:  
  77. 77:     /** @var NPresenterRequest */
  78. 78:     private $request;
  79. 79:  
  80. 80:     /** @var IPresenterResponse */
  81. 81:     private $response;
  82. 82:  
  83. 83:     /** @var int */
  84. 84:     private $phase;
  85. 85:  
  86. 86:     /** @var bool  automatically call canonicalize() */
  87. 87:     public $autoCanonicalize = TRUE;
  88. 88:  
  89. 89:     /** @var bool  use absolute Urls or paths? */
  90. 90:     public $absoluteUrls = FALSE;
  91. 91:  
  92. 92:     /** @var array */
  93. 93:     private $globalParams;
  94. 94:  
  95. 95:     /** @var array */
  96. 96:     private $globalState;
  97. 97:  
  98. 98:     /** @var array */
  99. 99:     private $globalStateSinces;
  100. 100:  
  101. 101:     /** @var string */
  102. 102:     private $action;
  103. 103:  
  104. 104:     /** @var string */
  105. 105:     private $view;
  106. 106:  
  107. 107:     /** @var string */
  108. 108:     private $layout 'layout';
  109. 109:  
  110. 110:     /** @var stdClass */
  111. 111:     private $payload;
  112. 112:  
  113. 113:     /** @var string */
  114. 114:     private $signalReceiver;
  115. 115:  
  116. 116:     /** @var string */
  117. 117:     private $signal;
  118. 118:  
  119. 119:     /** @var bool */
  120. 120:     private $ajaxMode;
  121. 121:  
  122. 122:     /** @var bool */
  123. 123:     private $startupCheck;
  124. 124:  
  125. 125:     /** @var NPresenterRequest */
  126. 126:     private $lastCreatedRequest;
  127. 127:  
  128. 128:     /** @var array */
  129. 129:     private $lastCreatedRequestFlag;
  130. 130:  
  131. 131:  
  132. 132:  
  133. 133:     /**
  134. 134:      * @return NPresenterRequest 
  135. 135:      */
  136. 136:     final public function getRequest()
  137. 137:     {
  138. 138:         return $this->request;
  139. 139:     }
  140. 140:  
  141. 141:  
  142. 142:  
  143. 143:     /**
  144. 144:      * Returns self.
  145. 145:      * @return NPresenter 
  146. 146:      */
  147. 147:     final public function getPresenter($need TRUE)
  148. 148:     {
  149. 149:         return $this;
  150. 150:     }
  151. 151:  
  152. 152:  
  153. 153:  
  154. 154:     /**
  155. 155:      * Returns a name that uniquely identifies component.
  156. 156:      * @return string 
  157. 157:      */
  158. 158:     final public function getUniqueId()
  159. 159:     {
  160. 160:         return '';
  161. 161:     }
  162. 162:  
  163. 163:  
  164. 164:  
  165. 165:     /********************* interface IPresenter ****************d*g**/
  166. 166:  
  167. 167:  
  168. 168:  
  169. 169:     /**
  170. 170:      * @param  NPresenterRequest 
  171. 171:      * @return IPresenterResponse 
  172. 172:      */
  173. 173:     public function run(NPresenterRequest $request)
  174. 174:     {
  175. 175:         try {
  176. 176:             // PHASE 1: STARTUP
  177. 177:             $this->phase self::PHASE_STARTUP;
  178. 178:             $this->request $request;
  179. 179:             $this->payload = (object) NULL;
  180. 180:             $this->setParent($this->getParent()$request->getPresenterName());
  181. 181:  
  182. 182:             $this->initGlobalParams();
  183. 183:             $this->startup();
  184. 184:             if (!$this->startupCheck{
  185. 185:                 $class $this->reflection->getMethod('startup')->getDeclaringClass()->getName();
  186. 186:                 trigger_error("Method $class::startup() or its descendant doesn't call parent::startup()."E_USER_WARNING);
  187. 187:             }
  188. 188:             // calls $this->action<Action>()
  189. 189:             $this->tryCall($this->formatActionMethod($this->getAction())$this->params);
  190. 190:  
  191. 191:             if ($this->autoCanonicalize{
  192. 192:                 $this->canonicalize();
  193. 193:             }
  194. 194:             if ($this->getHttpRequest()->isMethod('head')) {
  195. 195:                 $this->terminate();
  196. 196:             }
  197. 197:  
  198. 198:             // back compatibility
  199. 199:             if (method_exists($this'beforePrepare')) {
  200. 200:                 $this->beforePrepare();
  201. 201:                 trigger_error('beforePrepare() is deprecated; use createComponent{Name}() instead.'E_USER_WARNING);
  202. 202:             }
  203. 203:             if ($this->tryCall('prepare' $this->getView()$this->params)) {
  204. 204:                 trigger_error('prepare' ucfirst($this->getView()) '() is deprecated; use createComponent{Name}() instead.'E_USER_WARNING);
  205. 205:             }
  206. 206:  
  207. 207:             // PHASE 2: SIGNAL HANDLING
  208. 208:             $this->phase self::PHASE_SIGNAL;
  209. 209:             // calls $this->handle<Signal>()
  210. 210:             $this->processSignal();
  211. 211:  
  212. 212:             // PHASE 3: RENDERING VIEW
  213. 213:             $this->phase self::PHASE_RENDER;
  214. 214:  
  215. 215:             $this->beforeRender();
  216. 216:             // calls $this->render<View>()
  217. 217:             $this->tryCall($this->formatRenderMethod($this->getView())$this->params);
  218. 218:             $this->afterRender();
  219. 219:  
  220. 220:             // save component tree persistent state
  221. 221:             $this->saveGlobalState();
  222. 222:             if ($this->isAjax()) {
  223. 223:                 $this->payload->state $this->getGlobalState();
  224. 224:             }
  225. 225:  
  226. 226:             // finish template rendering
  227. 227:             $this->sendTemplate();
  228. 228:  
  229. 229:         catch (NAbortException $e{
  230. 230:             // continue with shutting down
  231. 231:         /* finally */ {
  232. 232:  
  233. 233:             // PHASE 4: SHUTDOWN
  234. 234:             $this->phase self::PHASE_SHUTDOWN;
  235. 235:  
  236. 236:             // back compatibility for use terminate() instead of sendPayload()
  237. 237:             if ($this->isAjax(&& !($this->response instanceof NForwardingResponse || $this->response instanceof NJsonResponse&& (array) $this->payload{
  238. 238:                 try $this->sendPayload()}
  239. 239:                 catch (NAbortException $e}
  240. 240:             }
  241. 241:  
  242. 242:             if ($this->hasFlashSession()) {
  243. 243:                 $this->getFlashSession()->setExpiration($this->response instanceof NRedirectingResponse '+ 30 seconds''+ 3 seconds');
  244. 244:             }
  245. 245:  
  246. 246:             $this->onShutdown($this$this->response);
  247. 247:             $this->shutdown($this->response);
  248. 248:  
  249. 249:             return $this->response;
  250. 250:         }
  251. 251:     }
  252. 252:  
  253. 253:  
  254. 254:  
  255. 255:     /**
  256. 256:      * Returns current presenter life cycle phase.
  257. 257:      * @return int 
  258. 258:      */
  259. 259:     final public function getPhase()
  260. 260:     {
  261. 261:         return $this->phase;
  262. 262:     }
  263. 263:  
  264. 264:  
  265. 265:  
  266. 266:     /**
  267. 267:      * @return void 
  268. 268:      */
  269. 269:     protected function startup()
  270. 270:     {
  271. 271:         $this->startupCheck TRUE;
  272. 272:     }
  273. 273:  
  274. 274:  
  275. 275:  
  276. 276:     /**
  277. 277:      * Common render method.
  278. 278:      * @return void 
  279. 279:      */
  280. 280:     protected function beforeRender()
  281. 281:     {
  282. 282:     }
  283. 283:  
  284. 284:  
  285. 285:  
  286. 286:     /**
  287. 287:      * Common render method.
  288. 288:      * @return void 
  289. 289:      */
  290. 290:     protected function afterRender()
  291. 291:     {
  292. 292:     }
  293. 293:  
  294. 294:  
  295. 295:  
  296. 296:     /**
  297. 297:      * @param  IPresenterResponse  optional catched exception
  298. 298:      * @return void 
  299. 299:      */
  300. 300:     protected function shutdown($response)
  301. 301:     {
  302. 302:     }
  303. 303:  
  304. 304:  
  305. 305:  
  306. 306:     /********************* signal handling ****************d*g**/
  307. 307:  
  308. 308:  
  309. 309:  
  310. 310:     /**
  311. 311:      * @return void 
  312. 312:      * @throws NBadSignalException
  313. 313:      */
  314. 314:     public function processSignal()
  315. 315:     {
  316. 316:         if ($this->signal === NULLreturn;
  317. 317:  
  318. 318:         $component $this->signalReceiver === '' $this $this->getComponent($this->signalReceiverFALSE);
  319. 319:         if ($component === NULL{
  320. 320:             throw new NBadSignalException("The signal receiver component '$this->signalReceiver' is not found.");
  321. 321:  
  322. 322:         elseif (!$component instanceof ISignalReceiver{
  323. 323:             throw new NBadSignalException("The signal receiver component '$this->signalReceiver' is not ISignalReceiver implementor.");
  324. 324:         }
  325. 325:  
  326. 326:         // auto invalidate
  327. 327:         if ($this->oldLayoutMode && $component instanceof IRenderable{
  328. 328:             $component->invalidateControl();
  329. 329:         }
  330. 330:  
  331. 331:         $component->signalReceived($this->signal);
  332. 332:         $this->signal NULL;
  333. 333:     }
  334. 334:  
  335. 335:  
  336. 336:  
  337. 337:     /**
  338. 338:      * Returns pair signal receiver and name.
  339. 339:      * @return array|NULL
  340. 340:      */
  341. 341:     final public function getSignal()
  342. 342:     {
  343. 343:         return $this->signal === NULL NULL array($this->signalReceiver$this->signal);
  344. 344:     }
  345. 345:  
  346. 346:  
  347. 347:  
  348. 348:     /**
  349. 349:      * Checks if the signal receiver is the given one.
  350. 350:      * @param  mixed  component or its id
  351. 351:      * @param  string signal name (optional)
  352. 352:      * @return bool 
  353. 353:      */
  354. 354:     final public function isSignalReceiver($component$signal NULL)
  355. 355:     {
  356. 356:         if ($component instanceof NComponent{
  357. 357:             $component $component === $this '' $component->lookupPath(__CLASS__TRUE);
  358. 358:         }
  359. 359:  
  360. 360:         if ($this->signal === NULL{
  361. 361:             return FALSE;
  362. 362:  
  363. 363:         elseif ($signal === TRUE{
  364. 364:             return $component === ''
  365. 365:                 || strncmp($this->signalReceiver '-'$component '-'strlen($component1=== 0;
  366. 366:  
  367. 367:         elseif ($signal === NULL{
  368. 368:             return $this->signalReceiver === $component;
  369. 369:  
  370. 370:         else {
  371. 371:             return $this->signalReceiver === $component && strcasecmp($signal$this->signal=== 0;
  372. 372:         }
  373. 373:     }
  374. 374:  
  375. 375:  
  376. 376:  
  377. 377:     /********************* rendering ****************d*g**/
  378. 378:  
  379. 379:  
  380. 380:  
  381. 381:     /**
  382. 382:      * Returns current action name.
  383. 383:      * @return string 
  384. 384:      */
  385. 385:     final public function getAction($fullyQualified FALSE)
  386. 386:     {
  387. 387:         return $fullyQualified ':' $this->getName(':' $this->action $this->action;
  388. 388:     }
  389. 389:  
  390. 390:  
  391. 391:  
  392. 392:     /**
  393. 393:      * Changes current action. Only alphanumeric characters are allowed.
  394. 394:      * @param  string 
  395. 395:      * @return void 
  396. 396:      */
  397. 397:     public function changeAction($action)
  398. 398:     {
  399. 399:         if (preg_match("#^[a-zA-Z0-9][a-zA-Z0-9_\x7f-\xff]*$#"$action)) {
  400. 400:             $this->action $action;
  401. 401:             $this->view $action;
  402. 402:  
  403. 403:         else {
  404. 404:             throw new NBadRequestException("Action name '$action' is not alphanumeric string.");
  405. 405:         }
  406. 406:     }
  407. 407:  
  408. 408:  
  409. 409:  
  410. 410:     /**
  411. 411:      * Returns current view.
  412. 412:      * @return string 
  413. 413:      */
  414. 414:     final public function getView()
  415. 415:     {
  416. 416:         return $this->view;
  417. 417:     }
  418. 418:  
  419. 419:  
  420. 420:  
  421. 421:     /**
  422. 422:      * Changes current view. Any name is allowed.
  423. 423:      * @param  string 
  424. 424:      * @return NPresenter  provides a fluent interface
  425. 425:      */
  426. 426:     public function setView($view)
  427. 427:     {
  428. 428:         $this->view = (string) $view;
  429. 429:         return $this;
  430. 430:     }
  431. 431:  
  432. 432:  
  433. 433:  
  434. 434:     /**
  435. 435:      * Returns current layout name.
  436. 436:      * @return string|FALSE
  437. 437:      */
  438. 438:     final public function getLayout()
  439. 439:     {
  440. 440:         return $this->layout;
  441. 441:     }
  442. 442:  
  443. 443:  
  444. 444:  
  445. 445:     /**
  446. 446:      * Changes or disables layout.
  447. 447:      * @param  string|FALSE
  448. 448:      * @return NPresenter  provides a fluent interface
  449. 449:      */
  450. 450:     public function setLayout($layout)
  451. 451:     {
  452. 452:         $this->layout = (string) $layout;
  453. 453:         return $this;
  454. 454:     }
  455. 455:  
  456. 456:  
  457. 457:  
  458. 458:     /**
  459. 459:      * @return void 
  460. 460:      * @throws NBadRequestException if no template found
  461. 461:      * @throws NAbortException
  462. 462:      */
  463. 463:     public function sendTemplate()
  464. 464:     {
  465. 465:         $template $this->getTemplate();
  466. 466:         if (!$templatereturn;
  467. 467:  
  468. 468:         if ($template instanceof IFileTemplate && !$template->getFile()) {
  469. 469:  
  470. 470:             // content template
  471. 471:             $files $this->formatTemplateFiles($this->getName()$this->view);
  472. 472:             foreach ($files as $file{
  473. 473:                 if (is_file($file)) {
  474. 474:                     $template->setFile($file);
  475. 475:                     break;
  476. 476:                 }
  477. 477:             }
  478. 478:  
  479. 479:             if (!$template->getFile()) {
  480. 480:                 $file str_replace(NEnvironment::getVariable('templatesDir')"\xE2\x80\xA6"reset($files));
  481. 481:                 throw new NBadRequestException("Page not found. Missing template '$file'.");
  482. 482:             }
  483. 483:  
  484. 484:             // layout template
  485. 485:             if ($this->layout{
  486. 486:                 foreach ($this->formatLayoutTemplateFiles($this->getName()$this->layoutas $file{
  487. 487:                     if (is_file($file)) {
  488. 488:                         if ($this->oldLayoutMode{
  489. 489:                             $template->content clone $template;
  490. 490:                             $template->setFile($file);
  491. 491:                         else {
  492. 492:                             $template->layout $template->_extends $file;
  493. 493:                         }
  494. 494:                         break;
  495. 495:                     }
  496. 496:                 }
  497. 497:             }
  498. 498:         }
  499. 499:  
  500. 500:         if ($this->isAjax()) // TODO!
  501. 501:             NSnippetHelper::$outputAllowed FALSE;
  502. 502:             $template->render();
  503. 503:             $this->sendPayload();
  504. 504:         }
  505. 505:  
  506. 506:         $this->terminate(new NRenderResponse($template));
  507. 507:     }
  508. 508:  
  509. 509:  
  510. 510:  
  511. 511:     /**
  512. 512:      * Formats layout template file names.
  513. 513:      * @param  string 
  514. 514:      * @param  string 
  515. 515:      * @return array 
  516. 516:      */
  517. 517:     public function formatLayoutTemplateFiles($presenter$layout)
  518. 518:     {
  519. 519:         $root NEnvironment::getVariable('templatesDir');
  520. 520:         $presenter str_replace(':''Module/'$presenter);
  521. 521:         $module substr($presenter0(int) strrpos($presenter'/'));
  522. 522:         $base '';
  523. 523:         if ($root === NEnvironment::getVariable('presentersDir')) {
  524. 524:             $base 'templates/';
  525. 525:             if ($module === ''{
  526. 526:                 $presenter 'templates/' $presenter;
  527. 527:             else {
  528. 528:                 $presenter substr_replace($presenter'/templates'strrpos($presenter'/')0);
  529. 529:             }
  530. 530:         }
  531. 531:  
  532. 532:         return array(
  533. 533:             "$root/$presenter/@$layout.phtml",
  534. 534:             "$root/$presenter.@$layout.phtml",
  535. 535:             "$root/$module/$base@$layout.phtml",
  536. 536:             "$root/$base@$layout.phtml",
  537. 537:         );
  538. 538:     }
  539. 539:  
  540. 540:  
  541. 541:  
  542. 542:     /**
  543. 543:      * Formats view template file names.
  544. 544:      * @param  string 
  545. 545:      * @param  string 
  546. 546:      * @return array 
  547. 547:      */
  548. 548:     public function formatTemplateFiles($presenter$view)
  549. 549:     {
  550. 550:         $root NEnvironment::getVariable('templatesDir');
  551. 551:         $presenter str_replace(':''Module/'$presenter);
  552. 552:         $dir '';
  553. 553:         if ($root === NEnvironment::getVariable('presentersDir')) // special supported case
  554. 554:             $pos strrpos($presenter'/');
  555. 555:             $presenter $pos === FALSE 'templates/' $presenter substr_replace($presenter'/templates'$pos0);
  556. 556:             $dir 'templates/';
  557. 557:         }
  558. 558:         return array(
  559. 559:             "$root/$presenter/$view.phtml",
  560. 560:             "$root/$presenter.$view.phtml",
  561. 561:             "$root/$dir@global.$view.phtml",
  562. 562:         );
  563. 563:     }
  564. 564:  
  565. 565:  
  566. 566:  
  567. 567:     /**
  568. 568:      * Formats action method name.
  569. 569:      * @param  string 
  570. 570:      * @return string 
  571. 571:      */
  572. 572:     protected static function formatActionMethod($action)
  573. 573:     {
  574. 574:         return 'action' $action;
  575. 575:     }
  576. 576:  
  577. 577:  
  578. 578:  
  579. 579:     /**
  580. 580:      * Formats render view method name.
  581. 581:      * @param  string 
  582. 582:      * @return string 
  583. 583:      */
  584. 584:     protected static function formatRenderMethod($view)
  585. 585:     {
  586. 586:         return 'render' $view;
  587. 587:     }
  588. 588:  
  589. 589:  
  590. 590:  
  591. 591:     /**
  592. 592:      * @deprecated
  593. 593:      */
  594. 594:     protected function renderTemplate()
  595. 595:     {
  596. 596:         throw new DeprecatedException(__METHOD__ . '() is deprecated; use $presenter->sendTemplate() instead.');
  597. 597:     }
  598. 598:  
  599. 599:  
  600. 600:  
  601. 601:     /********************* partial AJAX rendering ****************d*g**/
  602. 602:  
  603. 603:  
  604. 604:  
  605. 605:     /**
  606. 606:      * @return stdClass 
  607. 607:      */
  608. 608:     final public function getPayload()
  609. 609:     {
  610. 610:         return $this->payload;
  611. 611:     }
  612. 612:  
  613. 613:  
  614. 614:  
  615. 615:     /**
  616. 616:      * Is AJAX request?
  617. 617:      * @return bool 
  618. 618:      */
  619. 619:     public function isAjax()
  620. 620:     {
  621. 621:         if ($this->ajaxMode === NULL{
  622. 622:             $this->ajaxMode $this->getHttpRequest()->isAjax();
  623. 623:         }
  624. 624:         return $this->ajaxMode;
  625. 625:     }
  626. 626:  
  627. 627:  
  628. 628:  
  629. 629:     /**
  630. 630:      * Sends AJAX payload to the output.
  631. 631:      * @return void 
  632. 632:      * @throws NAbortException
  633. 633:      */
  634. 634:     protected function sendPayload()
  635. 635:     {
  636. 636:         $this->terminate(new NJsonResponse($this->payload));
  637. 637:     }
  638. 638:  
  639. 639:  
  640. 640:  
  641. 641:     /**
  642. 642:      * @deprecated
  643. 643:      */
  644. 644:     public function getAjaxDriver()
  645. 645:     {
  646. 646:         throw new DeprecatedException(__METHOD__ . '() is deprecated; use $presenter->payload instead.');
  647. 647:     }
  648. 648:  
  649. 649:  
  650. 650:  
  651. 651:     /********************* navigation & flow ****************d*g**/
  652. 652:  
  653. 653:  
  654. 654:  
  655. 655:     /**
  656. 656:      * Forward to another presenter or action.
  657. 657:      * @param  string|NPresenterRequest
  658. 658:      * @param  array|mixed
  659. 659:      * @return void 
  660. 660:      * @throws NAbortException
  661. 661:      */
  662. 662:     public function forward($destination$args array())
  663. 663:     {
  664. 664:         if ($destination instanceof NPresenterRequest{
  665. 665:             $this->terminate(new NForwardingResponse($destination));
  666. 666:  
  667. 667:         elseif (!is_array($args)) {
  668. 668:             $args func_get_args();
  669. 669:             array_shift($args);
  670. 670:         }
  671. 671:  
  672. 672:         $this->createRequest($this$destination$args'forward');
  673. 673:         $this->terminate(new NForwardingResponse($this->lastCreatedRequest));
  674. 674:     }
  675. 675:  
  676. 676:  
  677. 677:  
  678. 678:     /**
  679. 679:      * Redirect to another URL and ends presenter execution.
  680. 680:      * @param  string 
  681. 681:      * @param  int HTTP error code
  682. 682:      * @return void 
  683. 683:      * @throws NAbortException
  684. 684:      */
  685. 685:     public function redirectUri($uri$code NULL)
  686. 686:     {
  687. 687:         if ($this->isAjax()) {
  688. 688:             $this->payload->redirect = (string) $uri;
  689. 689:             $this->sendPayload();
  690. 690:  
  691. 691:         elseif (!$code{
  692. 692:             $code $this->getHttpRequest()->isMethod('post'IHttpResponse::S303_POST_GET IHttpResponse::S302_FOUND;
  693. 693:         }
  694. 694:         $this->terminate(new NRedirectingResponse($uri$code));
  695. 695:     }
  696. 696:  
  697. 697:  
  698. 698:  
  699. 699:     /**
  700. 700:      * NLink to myself.
  701. 701:      * @return string 
  702. 702:      */
  703. 703:     public function backlink()
  704. 704:     {
  705. 705:         return $this->getAction(TRUE);
  706. 706:     }
  707. 707:  
  708. 708:  
  709. 709:  
  710. 710:     /**
  711. 711:      * Returns the last created NPresenterRequest.
  712. 712:      * @return NPresenterRequest 
  713. 713:      */
  714. 714:     public function getLastCreatedRequest()
  715. 715:     {
  716. 716:         return $this->lastCreatedRequest;
  717. 717:     }
  718. 718:  
  719. 719:  
  720. 720:  
  721. 721:     /**
  722. 722:      * Returns the last created NPresenterRequest flag.
  723. 723:      * @param  string 
  724. 724:      * @return bool 
  725. 725:      */
  726. 726:     public function getLastCreatedRequestFlag($flag)
  727. 727:     {
  728. 728:         return !empty($this->lastCreatedRequestFlag[$flag]);
  729. 729:     }
  730. 730:  
  731. 731:  
  732. 732:  
  733. 733:     /**
  734. 734:      * Correctly terminates presenter.
  735. 735:      * @param  IPresenterResponse 
  736. 736:      * @return void 
  737. 737:      * @throws NAbortException
  738. 738:      */
  739. 739:     public function terminate(IPresenterResponse $response NULL)
  740. 740:     {
  741. 741:         $this->response $response;
  742. 742:         throw new NAbortException();
  743. 743:     }
  744. 744:  
  745. 745:  
  746. 746:  
  747. 747:     /**
  748. 748:      * Conditional redirect to canonicalized URI.
  749. 749:      * @return void 
  750. 750:      * @throws NAbortException
  751. 751:      */
  752. 752:     public function canonicalize()
  753. 753:     {
  754. 754:         if (!$this->isAjax(&& ($this->request->isMethod('get'|| $this->request->isMethod('head'))) {
  755. 755:             $uri $this->createRequest($this$this->action$this->getGlobalState($this->request->params'redirectX');
  756. 756:             if ($uri !== NULL && !$this->getHttpRequest()->getUri()->isEqual($uri)) {
  757. 757:                 $this->terminate(new NRedirectingResponse($uriIHttpResponse::S301_MOVED_PERMANENTLY));
  758. 758:             }
  759. 759:         }
  760. 760:     }
  761. 761:  
  762. 762:  
  763. 763:  
  764. 764:     /**
  765. 765:      * Attempts to cache the sent entity by its last modification date
  766. 766:      * @param  int    last modified time as unix timestamp
  767. 767:      * @param  string strong entity tag validator
  768. 768:      * @param  mixed  optional expiration time
  769. 769:      * @return int    date of the client's cache version, if available
  770. 770:      * @throws NAbortException
  771. 771:      */
  772. 772:     public function lastModified($lastModified$etag NULL$expire NULL)
  773. 773:     {
  774. 774:         if (!NEnvironment::isProduction()) {
  775. 775:             return NULL;
  776. 776:         }
  777. 777:  
  778. 778:         $httpResponse $this->getHttpResponse();
  779. 779:         $match FALSE;
  780. 780:  
  781. 781:         if ($lastModified 0{
  782. 782:             $httpResponse->setHeader('Last-Modified'NHttpResponse::date($lastModified));
  783. 783:         }
  784. 784:  
  785. 785:         if ($etag != NULL// intentionally ==
  786. 786:             $etag '"' addslashes($etag'"';
  787. 787:             $httpResponse->setHeader('ETag'$etag);
  788. 788:         }
  789. 789:  
  790. 790:         if ($expire !== NULL{
  791. 791:             $httpResponse->expire($expire);
  792. 792:         }
  793. 793:  
  794. 794:         $ifNoneMatch $this->getHttpRequest()->getHeader('if-none-match');
  795. 795:         $ifModifiedSince $this->getHttpRequest()->getHeader('if-modified-since');
  796. 796:         if ($ifModifiedSince !== NULL{
  797. 797:             $ifModifiedSince strtotime($ifModifiedSince);
  798. 798:         }
  799. 799:  
  800. 800:         if ($ifNoneMatch !== NULL{
  801. 801:             if ($ifNoneMatch === '*'{
  802. 802:                 $match TRUE// match, check if-modified-since
  803. 803:  
  804. 804:             elseif ($etag == NULL || strpos(' ' strtr($ifNoneMatch",\t"'  ')' ' $etag=== FALSE{
  805. 805:                 return $ifModifiedSince// no match, ignore if-modified-since
  806. 806:  
  807. 807:             else {
  808. 808:                 $match TRUE// match, check if-modified-since
  809. 809:             }
  810. 810:         }
  811. 811:  
  812. 812:         if ($ifModifiedSince !== NULL{
  813. 813:             if ($lastModified && $lastModified <= $ifModifiedSince{
  814. 814:                 $match TRUE;
  815. 815:  
  816. 816:             else {
  817. 817:                 return $ifModifiedSince;
  818. 818:             }
  819. 819:         }
  820. 820:  
  821. 821:         if ($match{
  822. 822:             $httpResponse->setCode(IHttpResponse::S304_NOT_MODIFIED);
  823. 823:             $httpResponse->setHeader('Content-Length''0');
  824. 824:             $this->terminate();
  825. 825:  
  826. 826:         else {
  827. 827:             return $ifModifiedSince;
  828. 828:         }
  829. 829:  
  830. 830:         return NULL;
  831. 831:     }
  832. 832:  
  833. 833:  
  834. 834:  
  835. 835:     /**
  836. 836:      * PresenterRequest/URL factory.
  837. 837:      * @param  NPresenterComponent  base
  838. 838:      * @param  string   destination in format "[[module:]presenter:]action" or "signal!"
  839. 839:      * @param  array    array of arguments
  840. 840:      * @param  string   forward|redirect|link
  841. 841:      * @return string   URL
  842. 842:      * @throws NInvalidLinkException
  843. 843:      * @ignore internal
  844. 844:      */
  845. 845:     final protected function createRequest($component$destinationarray $args$mode)
  846. 846:     {
  847. 847:         // note: createRequest supposes that saveState(), run() & tryCall() behaviour is final
  848. 848:  
  849. 849:         // cached services for better performance
  850. 850:         static $presenterLoader$router$httpRequest;
  851. 851:         if ($presenterLoader === NULL{
  852. 852:             $presenterLoader $this->getApplication()->getPresenterLoader();
  853. 853:             $router $this->getApplication()->getRouter();
  854. 854:             $httpRequest $this->getHttpRequest();
  855. 855:         }
  856. 856:  
  857. 857:         $this->lastCreatedRequest $this->lastCreatedRequestFlag NULL;
  858. 858:  
  859. 859:         // PARSE DESTINATION
  860. 860:         // 1) fragment
  861. 861:         $a strpos($destination'#');
  862. 862:         if ($a === FALSE{
  863. 863:             $fragment '';
  864. 864:         else {
  865. 865:             $fragment substr($destination$a);
  866. 866:             $destination substr($destination0$a);
  867. 867:         }
  868. 868:  
  869. 869:         // 2) ?query syntax
  870. 870:         $a strpos($destination'?');
  871. 871:         if ($a !== FALSE{
  872. 872:             parse_str(substr($destination$a 1)$args)// requires disabled magic quotes
  873. 873:             $destination substr($destination0$a);
  874. 874:         }
  875. 875:  
  876. 876:         // 3) URL scheme
  877. 877:         $a strpos($destination'//');
  878. 878:         if ($a === FALSE{
  879. 879:             $scheme FALSE;
  880. 880:         else {
  881. 881:             $scheme substr($destination0$a);
  882. 882:             $destination substr($destination$a 2);
  883. 883:         }
  884. 884:  
  885. 885:         // 4) signal or empty
  886. 886:         if (!($component instanceof NPresenter|| substr($destination-1=== '!'{
  887. 887:             $signal rtrim($destination'!');
  888. 888:             $a strrpos($signal':');
  889. 889:             if ($a !== FALSE{
  890. 890:                 $component $component->getComponent(strtr(substr($signal0$a)':''-'));
  891. 891:                 $signal = (string) substr($signal$a 1);
  892. 892:             }
  893. 893:             if ($signal == NULL{  // intentionally ==
  894. 894:                 throw new NInvalidLinkException("Signal must be non-empty string.");
  895. 895:             }
  896. 896:             $destination 'this';
  897. 897:         }
  898. 898:  
  899. 899:         if ($destination == NULL{  // intentionally ==
  900. 900:             throw new NInvalidLinkException("Destination must be non-empty string.");
  901. 901:         }
  902. 902:  
  903. 903:         // 5) presenter: action
  904. 904:         $current FALSE;
  905. 905:         $a strrpos($destination':');
  906. 906:         if ($a === FALSE{
  907. 907:             $action $destination === 'this' $this->action $destination;
  908. 908:             $presenter $this->getName();
  909. 909:             $presenterClass $this->getClass();
  910. 910:  
  911. 911:         else {
  912. 912:             $action = (string) substr($destination$a 1);
  913. 913:             if ($destination[0=== ':'// absolute
  914. 914:                 if ($a 2{
  915. 915:                     throw new NInvalidLinkException("Missing presenter name in '$destination'.");
  916. 916:                 }
  917. 917:                 $presenter substr($destination1$a 1);
  918. 918:  
  919. 919:             else // relative
  920. 920:                 $presenter $this->getName();
  921. 921:                 $b strrpos($presenter':');
  922. 922:                 if ($b === FALSE// no module
  923. 923:                     $presenter substr($destination0$a);
  924. 924:                 else // with module
  925. 925:                     $presenter substr($presenter0$b 1substr($destination0$a);
  926. 926:                 }
  927. 927:             }
  928. 928:             $presenterClass $presenterLoader->getPresenterClass($presenter);
  929. 929:         }
  930. 930:  
  931. 931:         // PROCESS SIGNAL ARGUMENTS
  932. 932:         if (isset($signal)) // $component must be IStatePersistent
  933. 933:             $class get_class($component);
  934. 934:             if ($signal === 'this'// means "no signal"
  935. 935:                 $signal '';
  936. 936:                 if (array_key_exists(0$args)) {
  937. 937:                     throw new NInvalidLinkException("Extra parameter for signal '$class:$signal!'.");
  938. 938:                 }
  939. 939:  
  940. 940:             elseif (strpos($signalself::NAME_SEPARATOR=== FALSE// TODO: NAppForm exception
  941. 941:                 // counterpart of signalReceived() & tryCall()
  942. 942:                 $method $component->formatSignalMethod($signal);
  943. 943:                 if (!NPresenterHelpers::isMethodCallable($class$method)) {
  944. 944:                     throw new NInvalidLinkException("Unknown signal '$class:$signal!'.");
  945. 945:                 }
  946. 946:                 if ($args// convert indexed parameters to named
  947. 947:                     NPresenterHelpers::argsToParams($class$method$args);
  948. 948:                 }
  949. 949:             }
  950. 950:  
  951. 951:             // counterpart of IStatePersistent
  952. 952:             if ($args && array_intersect_key($argsNPresenterHelpers::getPersistentParams($class))) {
  953. 953:                 $component->saveState($args);
  954. 954:             }
  955. 955:  
  956. 956:             if ($args && $component !== $this{
  957. 957:                 $prefix $component->getUniqueId(self::NAME_SEPARATOR;
  958. 958:                 foreach ($args as $key => $val{
  959. 959:                     unset($args[$key]);
  960. 960:                     $args[$prefix $key$val;
  961. 961:                 }
  962. 962:             }
  963. 963:         }
  964. 964:  
  965. 965:         // PROCESS ARGUMENTS
  966. 966:         if (is_subclass_of($presenterClass__CLASS__)) {
  967. 967:             if ($action === ''{
  968. 968:                 /*$action = $presenterClass::$defaultAction;*/ // in PHP 5.3
  969. 969:                 $action self::$defaultAction;
  970. 970:             }
  971. 971:  
  972. 972:             $current ($action === '*' || $action === $this->action&& $presenterClass === $this->getClass()// TODO
  973. 973:  
  974. 974:             if ($args || $destination === 'this'{
  975. 975:                 // counterpart of run() & tryCall()
  976. 976:                  // in PHP 5.3
  977. 977:                 $method call_user_func(array($presenterClass'formatActionMethod')$action);
  978. 978:                 if (!NPresenterHelpers::isMethodCallable($presenterClass$method)) {
  979. 979:                      // in PHP 5.3
  980. 980:                     $method call_user_func(array($presenterClass'formatRenderMethod')$action);
  981. 981:                     if (!NPresenterHelpers::isMethodCallable($presenterClass$method)) {
  982. 982:                         $method NULL;
  983. 983:                     }
  984. 984:                 }
  985. 985:  
  986. 986:                 // convert indexed parameters to named
  987. 987:                 if ($method === NULL{
  988. 988:                     if (array_key_exists(0$args)) {
  989. 989:                         throw new NInvalidLinkException("Extra parameter for '$presenter:$action'.");
  990. 990:                     }
  991. 991:  
  992. 992:                 elseif ($destination === 'this'{
  993. 993:                     NPresenterHelpers::argsToParams($presenterClass$method$args$this->params);
  994. 994:  
  995. 995:                 else {
  996. 996:                     NPresenterHelpers::argsToParams($presenterClass$method$args);
  997. 997:                 }
  998. 998:             }
  999. 999:  
  1000. 1000:             // counterpart of IStatePersistent
  1001. 1001:             if ($args && array_intersect_key($argsNPresenterHelpers::getPersistentParams($presenterClass))) {
  1002. 1002:                 $this->saveState($args$presenterClass);
  1003. 1003:             }
  1004. 1004:  
  1005. 1005:             $globalState $this->getGlobalState($destination === 'this' NULL $presenterClass);
  1006. 1006:             if ($current && $args{
  1007. 1007:                 $tmp $globalState $this->params;
  1008. 1008:                 foreach ($args as $key => $val{
  1009. 1009:                     if ((string) $val !== (isset($tmp[$key]? (string) $tmp[$key'')) {
  1010. 1010:                         $current FALSE;
  1011. 1011:                         break;
  1012. 1012:                     }
  1013. 1013:                 }
  1014. 1014:             }
  1015. 1015:             $args += $globalState;
  1016. 1016:         }
  1017. 1017:  
  1018. 1018:         // ADD ACTION & SIGNAL & FLASH
  1019. 1019:         $args[self::ACTION_KEY$action;
  1020. 1020:         if (!empty($signal)) {
  1021. 1021:             $args[self::SIGNAL_KEY$component->getParamId($signal);
  1022. 1022:             $current $current && $args[self::SIGNAL_KEY=== $this->getParam(self::SIGNAL_KEY);
  1023. 1023:         }
  1024. 1024:         if (($mode === 'redirect' || $mode === 'forward'&& $this->hasFlashSession()) {
  1025. 1025:             $args[self::FLASH_KEY$this->getParam(self::FLASH_KEY);
  1026. 1026:         }
  1027. 1027:  
  1028. 1028:         $this->lastCreatedRequest new NPresenterRequest(
  1029. 1029:             $presenter,
  1030. 1030:             NPresenterRequest::FORWARD,
  1031. 1031:             $args,
  1032. 1032:             array(),
  1033. 1033:             array()
  1034. 1034:         );
  1035. 1035:         $this->lastCreatedRequestFlag array('current' => $current);
  1036. 1036:  
  1037. 1037:         if ($mode === 'forward'return;
  1038. 1038:  
  1039. 1039:         // CONSTRUCT URL
  1040. 1040:         $uri $router->constructUrl($this->lastCreatedRequest$httpRequest);
  1041. 1041:         if ($uri === NULL{
  1042. 1042:             unset($args[self::ACTION_KEY]);
  1043. 1043:             $params urldecode(http_build_query($argsNULL', '));
  1044. 1044:             throw new NInvalidLinkException("No route for $presenter:$action($params)");
  1045. 1045:         }
  1046. 1046:  
  1047. 1047:         // make URL relative if possible
  1048. 1048:         if ($mode === 'link' && $scheme === FALSE && !$this->absoluteUrls{
  1049. 1049:             $hostUri $httpRequest->getUri()->getHostUri();
  1050. 1050:             if (strncmp($uri$hostUristrlen($hostUri)) === 0{
  1051. 1051:                 $uri substr($uristrlen($hostUri));
  1052. 1052:             }
  1053. 1053:         }
  1054. 1054:  
  1055. 1055:         return $uri $fragment;
  1056. 1056:     }
  1057. 1057:  
  1058. 1058:  
  1059. 1059:  
  1060. 1060:     /**
  1061. 1061:      * Invalid link handler. Descendant can override this method to change default behaviour.
  1062. 1062:      * @param  NInvalidLinkException 
  1063. 1063:      * @return string 
  1064. 1064:      * @throws NInvalidLinkException
  1065. 1065:      */
  1066. 1066:     protected function handleInvalidLink($e)
  1067. 1067:     {
  1068. 1068:         if (self::$invalidLinkMode === NULL{
  1069. 1069:             self::$invalidLinkMode NEnvironment::isProduction()
  1070. 1070:                 ? self::INVALID_LINK_SILENT self::INVALID_LINK_WARNING;
  1071. 1071:         }
  1072. 1072:  
  1073. 1073:         if (self::$invalidLinkMode === self::INVALID_LINK_SILENT{
  1074. 1074:             return '#';
  1075. 1075:  
  1076. 1076:         elseif (self::$invalidLinkMode === self::INVALID_LINK_WARNING{
  1077. 1077:             return 'error: ' htmlSpecialChars($e->getMessage());
  1078. 1078:  
  1079. 1079:         else // self::INVALID_LINK_EXCEPTION
  1080. 1080:             throw $e;
  1081. 1081:         }
  1082. 1082:     }
  1083. 1083:  
  1084. 1084:  
  1085. 1085:  
  1086. 1086:     /********************* interface IStatePersistent ****************d*g**/
  1087. 1087:  
  1088. 1088:  
  1089. 1089:  
  1090. 1090:     /**
  1091. 1091:      * Returns array of persistent components.
  1092. 1092:      * This default implementation detects components by class-level annotation @persistent(cmp1, cmp2).
  1093. 1093:      * @return array 
  1094. 1094:      */
  1095. 1095:     public static function getPersistentComponents()
  1096. 1096:     {
  1097. 1097:         return (array) NAnnotations::get(new ReflectionClass(func_get_arg(0))'persistent');
  1098. 1098:     }
  1099. 1099:  
  1100. 1100:  
  1101. 1101:  
  1102. 1102:     /**
  1103. 1103:      * Saves state information for all subcomponents to $this->globalState.
  1104. 1104:      * @return array 
  1105. 1105:      */
  1106. 1106:     private function getGlobalState($forClass NULL)
  1107. 1107:     {
  1108. 1108:         $sinces $this->globalStateSinces;
  1109. 1109:  
  1110. 1110:         if ($this->globalState === NULL{
  1111. 1111:             if ($this->phase >= self::PHASE_SHUTDOWN{
  1112. 1112:                 throw new InvalidStateException("NPresenter is shutting down, cannot save state.");
  1113. 1113:             }
  1114. 1114:  
  1115. 1115:             $state array();
  1116. 1116:             foreach ($this->globalParams as $id => $params{
  1117. 1117:                 $prefix $id self::NAME_SEPARATOR;
  1118. 1118:                 foreach ($params as $key => $val{
  1119. 1119:                     $state[$prefix $key$val;
  1120. 1120:                 }
  1121. 1121:             }
  1122. 1122:             $this->saveState($state$forClass);
  1123. 1123:  
  1124. 1124:             if ($sinces === NULL{
  1125. 1125:                 $sinces array();
  1126. 1126:                 foreach (NPresenterHelpers::getPersistentParams(get_class($this)) as $nm => $meta{
  1127. 1127:                     $sinces[$nm$meta['since'];
  1128. 1128:                 }
  1129. 1129:             }
  1130. 1130:  
  1131. 1131:             $components NPresenterHelpers::getPersistentComponents(get_class($this));
  1132. 1132:             $iterator $this->getComponents(TRUE'IStatePersistent');
  1133. 1133:             foreach ($iterator as $name => $component)
  1134. 1134:             {
  1135. 1135:                 if ($iterator->getDepth(=== 0{
  1136. 1136:                     // counts with RecursiveIteratorIterator::SELF_FIRST
  1137. 1137:                     $since isset($components[$name]['since']$components[$name]['since'FALSE// FALSE = nonpersistent
  1138. 1138:                 }
  1139. 1139:                 $prefix $component->getUniqueId(self::NAME_SEPARATOR;
  1140. 1140:                 $params array();
  1141. 1141:                 $component->saveState($params);
  1142. 1142:                 foreach ($params as $key => $val{
  1143. 1143:                     $state[$prefix $key$val;
  1144. 1144:                     $sinces[$prefix $key$since;
  1145. 1145:                 }
  1146. 1146:             }
  1147. 1147:  
  1148. 1148:         else {
  1149. 1149:             $state $this->globalState;
  1150. 1150:         }
  1151. 1151:  
  1152. 1152:         if ($forClass !== NULL{
  1153. 1153:             $since NULL;
  1154. 1154:             foreach ($state as $key => $foo{
  1155. 1155:                 if (!isset($sinces[$key])) {
  1156. 1156:                     $x strpos($keyself::NAME_SEPARATOR);
  1157. 1157:                     $x $x === FALSE $key substr($key0$x);
  1158. 1158:                     $sinces[$keyisset($sinces[$x]$sinces[$xFALSE;
  1159. 1159:                 }
  1160. 1160:                 if ($since !== $sinces[$key]{
  1161. 1161:                     $since $sinces[$key];
  1162. 1162:                     $ok $since && (is_subclass_of($forClass$since|| $forClass === $since);
  1163. 1163:                 }
  1164. 1164:                 if (!$ok{
  1165. 1165:                     unset($state[$key]);
  1166. 1166:                 }
  1167. 1167:             }
  1168. 1168:         }
  1169. 1169:  
  1170. 1170:         return $state;
  1171. 1171:     }
  1172. 1172:  
  1173. 1173:  
  1174. 1174:  
  1175. 1175:     /**
  1176. 1176:      * Permanently saves state information for all subcomponents to $this->globalState.
  1177. 1177:      * @return void 
  1178. 1178:      */
  1179. 1179:     protected function saveGlobalState()
  1180. 1180:     {
  1181. 1181:         // load lazy components
  1182. 1182:         foreach ($this->globalParams as $id => $foo{
  1183. 1183:             $this->getComponent($idFALSE);
  1184. 1184:         }
  1185. 1185:  
  1186. 1186:         $this->globalParams array();
  1187. 1187:         $this->globalState $this->getGlobalState();
  1188. 1188:     }
  1189. 1189:  
  1190. 1190:  
  1191. 1191:  
  1192. 1192:     /**
  1193. 1193:      * Initializes $this->globalParams, $this->signal & $this->signalReceiver, $this->action, $this->view. Called by run().
  1194. 1194:      * @return void 
  1195. 1195:      * @throws NBadRequestException if action name is not valid
  1196. 1196:      */
  1197. 1197:     private function initGlobalParams()
  1198. 1198:     {
  1199. 1199:         // init $this->globalParams
  1200. 1200:         $this->globalParams array();
  1201. 1201:         $selfParams array();
  1202. 1202:  
  1203. 1203:         $params $this->request->getParams();
  1204. 1204:         if ($this->isAjax()) {
  1205. 1205:             $params $this->request->getPost($params;
  1206. 1206:         }
  1207. 1207:  
  1208. 1208:         foreach ($params as $key => $value{
  1209. 1209:             $a strlen($keystrrpos($keyself::NAME_SEPARATOR-2FALSE;
  1210. 1210:             if ($a === FALSE{
  1211. 1211:                 $selfParams[$key$value;
  1212. 1212:             else {
  1213. 1213:                 $this->globalParams[substr($key0$a)][substr($key$a 1)$value;
  1214. 1214:             }
  1215. 1215:         }
  1216. 1216:  
  1217. 1217:         // init & validate $this->action & $this->view
  1218. 1218:         $this->changeAction(isset($selfParams[self::ACTION_KEY]$selfParams[self::ACTION_KEYself::$defaultAction);
  1219. 1219:  
  1220. 1220:         // init $this->signalReceiver and key 'signal' in appropriate params array
  1221. 1221:         $this->signalReceiver $this->getUniqueId();
  1222. 1222:         if (!empty($selfParams[self::SIGNAL_KEY])) {
  1223. 1223:             $param $selfParams[self::SIGNAL_KEY];
  1224. 1224:             $pos strrpos($param'-');
  1225. 1225:             if ($pos{
  1226. 1226:                 $this->signalReceiver substr($param0$pos);
  1227. 1227:                 $this->signal substr($param$pos 1);
  1228. 1228:             else {
  1229. 1229:                 $this->signalReceiver $this->getUniqueId();
  1230. 1230:                 $this->signal $param;
  1231. 1231:             }
  1232. 1232:             if ($this->signal == NULL// intentionally ==
  1233. 1233:                 $this->signal NULL;
  1234. 1234:             }
  1235. 1235:         }
  1236. 1236:  
  1237. 1237:         $this->loadState($selfParams);
  1238. 1238:     }
  1239. 1239:  
  1240. 1240:  
  1241. 1241:  
  1242. 1242:     /**
  1243. 1243:      * Pops parameters for specified component.
  1244. 1244:      * @param  string  component id
  1245. 1245:      * @return array 
  1246. 1246:      */
  1247. 1247:     final public function popGlobalParams($id)
  1248. 1248:     {
  1249. 1249:         if (isset($this->globalParams[$id])) {
  1250. 1250:             $res $this->globalParams[$id];
  1251. 1251:             unset($this->globalParams[$id]);
  1252. 1252:             return $res;
  1253. 1253:  
  1254. 1254:         else {
  1255. 1255:             return array();
  1256. 1256:         }
  1257. 1257:     }
  1258. 1258:  
  1259. 1259:  
  1260. 1260:  
  1261. 1261:     /********************* flash session ****************d*g**/
  1262. 1262:  
  1263. 1263:  
  1264. 1264:  
  1265. 1265:     /**
  1266. 1266:      * Checks if a flash session namespace exists.
  1267. 1267:      * @return bool 
  1268. 1268:      */
  1269. 1269:     public function hasFlashSession()
  1270. 1270:     {
  1271. 1271:         return !empty($this->params[self::FLASH_KEY])
  1272. 1272:             && $this->getSession()->hasNamespace('Nette.NApplication.Flash/' $this->params[self::FLASH_KEY]);
  1273. 1273:     }
  1274. 1274:  
  1275. 1275:  
  1276. 1276:  
  1277. 1277:     /**
  1278. 1278:      * Returns session namespace provided to pass temporary data between redirects.
  1279. 1279:      * @return NSessionNamespace 
  1280. 1280:      */
  1281. 1281:     public function getFlashSession()
  1282. 1282:     {
  1283. 1283:         if (empty($this->params[self::FLASH_KEY])) {
  1284. 1284:             $this->params[self::FLASH_KEYsubstr(md5(lcg_value())04);
  1285. 1285:         }
  1286. 1286:         return $this->getSession()->getNamespace('Nette.NApplication.Flash/' $this->params[self::FLASH_KEY]);
  1287. 1287:     }
  1288. 1288:  
  1289. 1289:  
  1290. 1290:  
  1291. 1291:     /********************* backend ****************d*g**/
  1292. 1292:  
  1293. 1293:  
  1294. 1294:  
  1295. 1295:     /**
  1296. 1296:      * @return IHttpRequest 
  1297. 1297:      */
  1298. 1298:     protected function getHttpRequest()
  1299. 1299:     {
  1300. 1300:         return NEnvironment::getHttpRequest();
  1301. 1301:     }
  1302. 1302:  
  1303. 1303:  
  1304. 1304:  
  1305. 1305:     /**
  1306. 1306:      * @return IHttpResponse 
  1307. 1307:      */
  1308. 1308:     protected function getHttpResponse()
  1309. 1309:     {
  1310. 1310:         return NEnvironment::getHttpResponse();
  1311. 1311:     }
  1312. 1312:  
  1313. 1313:  
  1314. 1314:  
  1315. 1315:     /**
  1316. 1316:      * @return NApplication 
  1317. 1317:      */
  1318. 1318:     public function getApplication()
  1319. 1319:     {
  1320. 1320:         return NEnvironment::getApplication();
  1321. 1321:     }
  1322. 1322:  
  1323. 1323:  
  1324. 1324:  
  1325. 1325:     /**
  1326. 1326:      * @return NSession 
  1327. 1327:      */
  1328. 1328:     private function getSession()
  1329. 1329:     {
  1330. 1330:         return NEnvironment::getSession();
  1331. 1331:     }
  1332. 1332: