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