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