PageRenderTime 103ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 2ms

/pradolite.php

https://bitbucket.org/freshflow/prado-fork-v3.10
PHP | 9635 lines | 9623 code | 1 blank | 11 comment | 266 complexity | 9963c86421231f6fd32c82a06ecb61a8 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0
  1. <?php
  2. /**
  3. * File Name: pradolite.php
  4. * Last Update: 2011/11/01 00:20:48
  5. * Generated By: buildscripts/phpbuilder/build.php
  6. *
  7. * This file is used in lieu of prado.php to boost PRADO application performance.
  8. * It is generated by expanding prado.php with included files.
  9. * Comments and trace statements are stripped off.
  10. *
  11. * Do not modify this file manually.
  12. */
  13. if(!defined('PRADO_DIR'))
  14. define('PRADO_DIR',dirname(__FILE__));
  15. if(!defined('PRADO_CHMOD'))
  16. define('PRADO_CHMOD',0777);
  17. class PradoBase
  18. {
  19. const CLASS_FILE_EXT='.php';
  20. private static $_aliases=array('System'=>PRADO_DIR);
  21. private static $_usings=array();
  22. private static $_application=null;
  23. private static $_logger=null;
  24. protected static $classExists = array();
  25. public static function getVersion()
  26. {
  27. return '3.1.10';
  28. }
  29. public static function initErrorHandlers()
  30. {
  31. set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting());
  32. set_exception_handler(array('PradoBase','exceptionHandler'));
  33. }
  34. public static function autoload($className)
  35. {
  36. include_once($className.self::CLASS_FILE_EXT);
  37. if(!class_exists($className,false) && !interface_exists($className,false))
  38. self::fatalError("Class file for '$className' cannot be found.");
  39. }
  40. public static function poweredByPrado($logoType=0)
  41. {
  42. $logoName=$logoType==1?'powered2':'powered';
  43. if(self::$_application!==null)
  44. {
  45. $am=self::$_application->getAssetManager();
  46. $url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
  47. }
  48. else
  49. $url='http://www.pradosoft.com/images/'.$logoName.'.gif';
  50. return '<a title="Powered by PRADO" href="http://www.pradosoft.com/" target="_blank"><img src="'.$url.'" style="border-width:0px;" alt="Powered by PRADO" /></a>';
  51. }
  52. public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
  53. {
  54. if(error_reporting()!=0)
  55. throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
  56. }
  57. public static function exceptionHandler($exception)
  58. {
  59. if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
  60. {
  61. $errorHandler->handleError(null,$exception);
  62. }
  63. else
  64. {
  65. echo $exception;
  66. }
  67. exit(1);
  68. }
  69. public static function setApplication($application)
  70. {
  71. if(self::$_application!==null)
  72. throw new TInvalidOperationException('prado_application_singleton_required');
  73. self::$_application=$application;
  74. }
  75. public static function getApplication()
  76. {
  77. return self::$_application;
  78. }
  79. public static function getFrameworkPath()
  80. {
  81. return PRADO_DIR;
  82. }
  83. public static function serialize($data)
  84. {
  85. $arr[0]=$data;
  86. return serialize($arr);
  87. }
  88. public static function unserialize($str)
  89. {
  90. $arr=unserialize($str);
  91. return isset($arr[0])?$arr[0]:null;
  92. }
  93. public static function createComponent($type)
  94. {
  95. if(!isset(self::$classExists[$type]))
  96. self::$classExists[$type] = class_exists($type, false);
  97. if( !isset(self::$_usings[$type]) && !self::$classExists[$type]) {
  98. self::using($type);
  99. self::$classExists[$type] = class_exists($type, false);
  100. }
  101. if( ($pos = strrpos($type, '.')) !== false)
  102. $type = substr($type,$pos+1);
  103. if(($n=func_num_args())>1)
  104. {
  105. $args = func_get_args();
  106. switch($n) {
  107. case 2:
  108. return new $type($args[1]);
  109. break;
  110. case 3:
  111. return new $type($args[1], $args[2]);
  112. break;
  113. case 4:
  114. return new $type($args[1], $args[2], $args[3]);
  115. break;
  116. case 5:
  117. return new $type($args[1], $args[2], $args[3], $args[4]);
  118. break;
  119. default:
  120. $s='$args[1]';
  121. for($i=2;$i<$n;++$i)
  122. $s.=",\$args[$i]";
  123. eval("\$component=new $type($s);");
  124. return $component;
  125. break;
  126. }
  127. }
  128. else
  129. return new $type;
  130. }
  131. public static function using($namespace,$checkClassExistence=true)
  132. {
  133. if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
  134. return;
  135. if(($pos=strrpos($namespace,'.'))===false) {
  136. try
  137. {
  138. include_once($namespace.self::CLASS_FILE_EXT);
  139. }
  140. catch(Exception $e)
  141. {
  142. if($checkClassExistence && !class_exists($namespace,false))
  143. throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
  144. else
  145. throw $e;
  146. }
  147. }
  148. else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
  149. {
  150. $className=substr($namespace,$pos+1);
  151. if($className==='*') {
  152. self::$_usings[$namespace]=$path;
  153. set_include_path(get_include_path().PATH_SEPARATOR.$path);
  154. }
  155. else {
  156. self::$_usings[$namespace]=$path;
  157. if(!$checkClassExistence || !class_exists($className,false))
  158. {
  159. try
  160. {
  161. include_once($path);
  162. }
  163. catch(Exception $e)
  164. {
  165. if($checkClassExistence && !class_exists($className,false))
  166. throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
  167. else
  168. throw $e;
  169. }
  170. }
  171. }
  172. }
  173. else
  174. throw new TInvalidDataValueException('prado_using_invalid',$namespace);
  175. }
  176. public static function getPathOfNamespace($namespace, $ext='')
  177. {
  178. if(self::CLASS_FILE_EXT === $ext || empty($ext))
  179. {
  180. if(isset(self::$_usings[$namespace]))
  181. return self::$_usings[$namespace];
  182. if(isset(self::$_aliases[$namespace]))
  183. return self::$_aliases[$namespace];
  184. }
  185. $segs = explode('.',$namespace);
  186. $alias = array_shift($segs);
  187. if(null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias)))
  188. return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file === '*') ? '' : DIRECTORY_SEPARATOR.$file.$ext);
  189. return null;
  190. }
  191. public static function getPathOfAlias($alias)
  192. {
  193. return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
  194. }
  195. protected static function getPathAliases()
  196. {
  197. return self::$_aliases;
  198. }
  199. public static function setPathOfAlias($alias,$path)
  200. {
  201. if(isset(self::$_aliases[$alias]))
  202. throw new TInvalidOperationException('prado_alias_redefined',$alias);
  203. else if(($rp=realpath($path))!==false && is_dir($rp))
  204. {
  205. if(strpos($alias,'.')===false)
  206. self::$_aliases[$alias]=$rp;
  207. else
  208. throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
  209. }
  210. else
  211. throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
  212. }
  213. public static function fatalError($msg)
  214. {
  215. echo '<h1>Fatal Error</h1>';
  216. echo '<p>'.$msg.'</p>';
  217. if(!function_exists('debug_backtrace'))
  218. return;
  219. echo '<h2>Debug Backtrace</h2>';
  220. echo '<pre>';
  221. $index=-1;
  222. foreach(debug_backtrace() as $t)
  223. {
  224. $index++;
  225. if($index==0) continue;
  226. echo '#'.$index.' ';
  227. if(isset($t['file']))
  228. echo basename($t['file']) . ':' . $t['line'];
  229. else
  230. echo '<PHP inner-code>';
  231. echo ' -- ';
  232. if(isset($t['class']))
  233. echo $t['class'] . $t['type'];
  234. echo $t['function'] . '(';
  235. if(isset($t['args']) && sizeof($t['args']) > 0)
  236. {
  237. $count=0;
  238. foreach($t['args'] as $item)
  239. {
  240. if(is_string($item))
  241. {
  242. $str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
  243. if (strlen($item) > 70)
  244. echo "'". substr($str, 0, 70) . "...'";
  245. else
  246. echo "'" . $str . "'";
  247. }
  248. else if (is_int($item) || is_float($item))
  249. echo $item;
  250. else if (is_object($item))
  251. echo get_class($item);
  252. else if (is_array($item))
  253. echo 'array(' . count($item) . ')';
  254. else if (is_bool($item))
  255. echo $item ? 'true' : 'false';
  256. else if ($item === null)
  257. echo 'NULL';
  258. else if (is_resource($item))
  259. echo get_resource_type($item);
  260. $count++;
  261. if (count($t['args']) > $count)
  262. echo ', ';
  263. }
  264. }
  265. echo ")\n";
  266. }
  267. echo '</pre>';
  268. exit(1);
  269. }
  270. public static function getUserLanguages()
  271. {
  272. static $languages=null;
  273. if($languages===null)
  274. {
  275. if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
  276. $languages[0]='en';
  277. else
  278. {
  279. $languages=array();
  280. foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
  281. {
  282. $array=explode(';q=',trim($language));
  283. $languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
  284. }
  285. arsort($languages);
  286. $languages=array_keys($languages);
  287. if(empty($languages))
  288. $languages[0]='en';
  289. }
  290. }
  291. return $languages;
  292. }
  293. public static function getPreferredLanguage()
  294. {
  295. static $language=null;
  296. if($language===null)
  297. {
  298. $langs=Prado::getUserLanguages();
  299. $lang=explode('-',$langs[0]);
  300. if(empty($lang[0]) || !ctype_alpha($lang[0]))
  301. $language='en';
  302. else
  303. $language=$lang[0];
  304. }
  305. return $language;
  306. }
  307. public static function trace($msg,$category='Uncategorized')
  308. {
  309. if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
  310. return;
  311. if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
  312. {
  313. $trace=debug_backtrace();
  314. if(isset($trace[0]['file']) && isset($trace[0]['line']))
  315. $msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
  316. $level=TLogger::DEBUG;
  317. }
  318. else
  319. $level=TLogger::INFO;
  320. self::log($msg,$level,$category);
  321. }
  322. public static function log($msg,$level=TLogger::INFO,$category='Uncategorized')
  323. {
  324. if(self::$_logger===null)
  325. self::$_logger=new TLogger;
  326. self::$_logger->log($msg,$level,$category);
  327. }
  328. public static function getLogger()
  329. {
  330. if(self::$_logger===null)
  331. self::$_logger=new TLogger;
  332. return self::$_logger;
  333. }
  334. public static function varDump($var,$depth=10,$highlight=false)
  335. {
  336. Prado::using('System.Util.TVarDumper');
  337. return TVarDumper::dump($var,$depth,$highlight);
  338. }
  339. public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
  340. {
  341. Prado::using('System.I18N.Translation');
  342. $app = Prado::getApplication()->getGlobalization(false);
  343. $params = array();
  344. foreach($parameters as $key => $value)
  345. $params['{'.$key.'}'] = $value;
  346. if($app===null || ($config = $app->getTranslationConfiguration())===null)
  347. return strtr($text, $params);
  348. if ($catalogue===null)
  349. $catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
  350. Translation::init($catalogue);
  351. $appCharset = $app===null ? '' : $app->getCharset();
  352. $defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
  353. if(empty($charset)) $charset = $appCharset;
  354. if(empty($charset)) $charset = $defaultCharset;
  355. return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset);
  356. }
  357. }
  358. class TReflectionClass extends ReflectionClass
  359. {
  360. }
  361. PradoBase::using('System.TComponent');
  362. PradoBase::using('System.Exceptions.TException');
  363. PradoBase::using('System.Util.TLogger');
  364. if(!class_exists('Prado',false))
  365. {
  366. class Prado extends PradoBase
  367. {
  368. }
  369. }
  370. spl_autoload_register(array('Prado','autoload'));
  371. Prado::initErrorHandlers();
  372. interface IModule
  373. {
  374. public function init($config);
  375. public function getID();
  376. public function setID($id);
  377. }
  378. interface IService
  379. {
  380. public function init($config);
  381. public function getID();
  382. public function setID($id);
  383. public function getEnabled();
  384. public function setEnabled($value);
  385. public function run();
  386. }
  387. interface ITextWriter
  388. {
  389. public function write($str);
  390. public function flush();
  391. }
  392. interface IUser
  393. {
  394. public function getName();
  395. public function setName($value);
  396. public function getIsGuest();
  397. public function setIsGuest($value);
  398. public function getRoles();
  399. public function setRoles($value);
  400. public function isInRole($role);
  401. public function saveToString();
  402. public function loadFromString($string);
  403. }
  404. interface IStatePersister
  405. {
  406. public function load();
  407. public function save($state);
  408. }
  409. interface ICache
  410. {
  411. public function get($id);
  412. public function set($id,$value,$expire=0,$dependency=null);
  413. public function add($id,$value,$expire=0,$dependency=null);
  414. public function delete($id);
  415. public function flush();
  416. }
  417. interface ICacheDependency
  418. {
  419. public function getHasChanged();
  420. }
  421. interface IRenderable
  422. {
  423. public function render($writer);
  424. }
  425. interface IBindable
  426. {
  427. public function dataBind();
  428. }
  429. interface IStyleable
  430. {
  431. public function getHasStyle();
  432. public function getStyle();
  433. public function clearStyle();
  434. }
  435. interface IActiveControl
  436. {
  437. public function getActiveControl();
  438. }
  439. interface ICallbackEventHandler
  440. {
  441. public function raiseCallbackEvent($eventArgument);
  442. }
  443. interface IDataRenderer
  444. {
  445. public function getData();
  446. public function setData($value);
  447. }
  448. class TApplicationComponent extends TComponent
  449. {
  450. public function getApplication()
  451. {
  452. return Prado::getApplication();
  453. }
  454. public function getService()
  455. {
  456. return Prado::getApplication()->getService();
  457. }
  458. public function getRequest()
  459. {
  460. return Prado::getApplication()->getRequest();
  461. }
  462. public function getResponse()
  463. {
  464. return Prado::getApplication()->getResponse();
  465. }
  466. public function getSession()
  467. {
  468. return Prado::getApplication()->getSession();
  469. }
  470. public function getUser()
  471. {
  472. return Prado::getApplication()->getUser();
  473. }
  474. public function publishAsset($assetPath,$className=null)
  475. {
  476. if($className===null)
  477. $className=get_class($this);
  478. $class=new ReflectionClass($className);
  479. $fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath;
  480. return $this->publishFilePath($fullPath);
  481. }
  482. public function publishFilePath($fullPath)
  483. {
  484. return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath);
  485. }
  486. }
  487. abstract class TModule extends TApplicationComponent implements IModule
  488. {
  489. private $_id;
  490. public function init($config)
  491. {
  492. }
  493. public function getID()
  494. {
  495. return $this->_id;
  496. }
  497. public function setID($value)
  498. {
  499. $this->_id=$value;
  500. }
  501. }
  502. abstract class TService extends TApplicationComponent implements IService
  503. {
  504. private $_id;
  505. private $_enabled=true;
  506. public function init($config)
  507. {
  508. }
  509. public function getID()
  510. {
  511. return $this->_id;
  512. }
  513. public function setID($value)
  514. {
  515. $this->_id=$value;
  516. }
  517. public function getEnabled()
  518. {
  519. return $this->_enabled;
  520. }
  521. public function setEnabled($value)
  522. {
  523. $this->_enabled=TPropertyValue::ensureBoolean($value);
  524. }
  525. public function run()
  526. {
  527. }
  528. }
  529. class TErrorHandler extends TModule
  530. {
  531. const ERROR_FILE_NAME='error';
  532. const EXCEPTION_FILE_NAME='exception';
  533. const SOURCE_LINES=12;
  534. private $_templatePath=null;
  535. public function init($config)
  536. {
  537. $this->getApplication()->setErrorHandler($this);
  538. }
  539. public function getErrorTemplatePath()
  540. {
  541. if($this->_templatePath===null)
  542. $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
  543. return $this->_templatePath;
  544. }
  545. public function setErrorTemplatePath($value)
  546. {
  547. if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath))
  548. $this->_templatePath=$templatePath;
  549. else
  550. throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value);
  551. }
  552. public function handleError($sender,$param)
  553. {
  554. static $handling=false;
  555. restore_error_handler();
  556. restore_exception_handler();
  557. if($handling)
  558. $this->handleRecursiveError($param);
  559. else
  560. {
  561. $handling=true;
  562. if(($response=$this->getResponse())!==null)
  563. $response->clear();
  564. if(!headers_sent())
  565. header('Content-Type: text/html; charset=UTF-8');
  566. if($param instanceof THttpException)
  567. $this->handleExternalError($param->getStatusCode(),$param);
  568. else if($this->getApplication()->getMode()===TApplicationMode::Debug)
  569. $this->displayException($param);
  570. else
  571. $this->handleExternalError(500,$param);
  572. }
  573. }
  574. protected static function hideSecurityRelated($value, $exception=null)
  575. {
  576. $aRpl = array();
  577. if($exception !== null && $exception instanceof Exception)
  578. {
  579. $aTrace = $exception->getTrace();
  580. foreach($aTrace as $item)
  581. {
  582. $file = $item['file'];
  583. $aRpl[dirname($file) . DIRECTORY_SEPARATOR] = '<hidden>' . DIRECTORY_SEPARATOR;
  584. }
  585. }
  586. $aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}';
  587. $aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}';
  588. $aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR;
  589. if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]);
  590. $aRpl = array_reverse($aRpl, true);
  591. return str_replace(array_keys($aRpl), $aRpl, $value);
  592. }
  593. protected function handleExternalError($statusCode,$exception)
  594. {
  595. if(!($exception instanceof THttpException))
  596. error_log($exception->__toString());
  597. $content=$this->getErrorTemplate($statusCode,$exception);
  598. $serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
  599. $isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug;
  600. $errorMessage = $exception->getMessage();
  601. if($isDebug)
  602. $version=$_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion();
  603. else
  604. {
  605. $version='';
  606. $errorMessage = self::hideSecurityRelated($errorMessage, $exception);
  607. }
  608. $tokens=array(
  609. '%%StatusCode%%' => "$statusCode",
  610. '%%ErrorMessage%%' => htmlspecialchars($errorMessage),
  611. '%%ServerAdmin%%' => $serverAdmin,
  612. '%%Version%%' => $version,
  613. '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
  614. );
  615. if($isDebug)
  616. header("HTTP/1.0 $statusCode ".$exception->getMessage(), true, TPropertyValue::ensureInteger($statusCode));
  617. else
  618. header("HTTP/1.0 $statusCode", true, TPropertyValue::ensureInteger($statusCode));
  619. echo strtr($content,$tokens);
  620. }
  621. protected function handleRecursiveError($exception)
  622. {
  623. if($this->getApplication()->getMode()===TApplicationMode::Debug)
  624. {
  625. echo "<html><head><title>Recursive Error</title></head>\n";
  626. echo "<body><h1>Recursive Error</h1>\n";
  627. echo "<pre>".$exception->__toString()."</pre>\n";
  628. echo "</body></html>";
  629. }
  630. else
  631. {
  632. error_log("Error happened while processing an existing error:\n".$exception->__toString());
  633. header('HTTP/1.0 500 Internal Error');
  634. }
  635. }
  636. protected function displayException($exception)
  637. {
  638. if(php_sapi_name()==='cli')
  639. {
  640. echo $exception->getMessage()."\n";
  641. echo $exception->getTraceAsString();
  642. return;
  643. }
  644. if($exception instanceof TTemplateException)
  645. {
  646. $fileName=$exception->getTemplateFile();
  647. $lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
  648. $source=$this->getSourceCode($lines,$exception->getLineNumber());
  649. if($fileName==='')
  650. $fileName='---embedded template---';
  651. $errorLine=$exception->getLineNumber();
  652. }
  653. else
  654. {
  655. if(($trace=$this->getExactTrace($exception))!==null)
  656. {
  657. $fileName=$trace['file'];
  658. $errorLine=$trace['line'];
  659. }
  660. else
  661. {
  662. $fileName=$exception->getFile();
  663. $errorLine=$exception->getLine();
  664. }
  665. $source=$this->getSourceCode(@file($fileName),$errorLine);
  666. }
  667. if($this->getApplication()->getMode()===TApplicationMode::Debug)
  668. $version=$_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion();
  669. else
  670. $version='';
  671. $tokens=array(
  672. '%%ErrorType%%' => get_class($exception),
  673. '%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
  674. '%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
  675. '%%SourceCode%%' => $source,
  676. '%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
  677. '%%Version%%' => $version,
  678. '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
  679. );
  680. $content=$this->getExceptionTemplate($exception);
  681. echo strtr($content,$tokens);
  682. }
  683. protected function getExceptionTemplate($exception)
  684. {
  685. $lang=Prado::getPreferredLanguage();
  686. $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html';
  687. if(!is_file($exceptionFile))
  688. $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html';
  689. if(($content=@file_get_contents($exceptionFile))===false)
  690. die("Unable to open exception template file '$exceptionFile'.");
  691. return $content;
  692. }
  693. protected function getErrorTemplate($statusCode,$exception)
  694. {
  695. $base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME;
  696. $lang=Prado::getPreferredLanguage();
  697. if(is_file("$base$statusCode-$lang.html"))
  698. $errorFile="$base$statusCode-$lang.html";
  699. else if(is_file("$base$statusCode.html"))
  700. $errorFile="$base$statusCode.html";
  701. else if(is_file("$base-$lang.html"))
  702. $errorFile="$base-$lang.html";
  703. else
  704. $errorFile="$base.html";
  705. if(($content=@file_get_contents($errorFile))===false)
  706. die("Unable to open error template file '$errorFile'.");
  707. return $content;
  708. }
  709. private function getExactTrace($exception)
  710. {
  711. $trace=$exception->getTrace();
  712. $result=null;
  713. if($exception instanceof TPhpErrorException)
  714. $result=isset($trace[0]['file'])?$trace[0]:$trace[1];
  715. else if($exception instanceof TInvalidOperationException)
  716. {
  717. if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
  718. $result=$this->getPropertyAccessTrace($trace,'__set');
  719. }
  720. if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
  721. return null;
  722. return $result;
  723. }
  724. private function getPropertyAccessTrace($trace,$pattern)
  725. {
  726. $result=null;
  727. foreach($trace as $t)
  728. {
  729. if(isset($t['function']) && $t['function']===$pattern)
  730. $result=$t;
  731. else
  732. break;
  733. }
  734. return $result;
  735. }
  736. private function getSourceCode($lines,$errorLine)
  737. {
  738. $beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
  739. $endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
  740. $source='';
  741. for($i=$beginLine;$i<$endLine;++$i)
  742. {
  743. if($i===$errorLine-1)
  744. {
  745. $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
  746. $source.="<div class=\"error\">".$line."</div>";
  747. }
  748. else
  749. $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
  750. }
  751. return $source;
  752. }
  753. private function addLink($message)
  754. {
  755. $baseUrl='http://www.pradosoft.com/docs/classdoc';
  756. return preg_replace('/\b(T[A-Z]\w+)\b/',"<a href=\"$baseUrl/\${1}\" target=\"_blank\">\${1}</a>",$message);
  757. }
  758. }
  759. class TList extends TComponent implements IteratorAggregate,ArrayAccess,Countable
  760. {
  761. private $_d=array();
  762. private $_c=0;
  763. private $_r=false;
  764. public function __construct($data=null,$readOnly=false)
  765. {
  766. if($data!==null)
  767. $this->copyFrom($data);
  768. $this->setReadOnly($readOnly);
  769. }
  770. public function getReadOnly()
  771. {
  772. return $this->_r;
  773. }
  774. protected function setReadOnly($value)
  775. {
  776. $this->_r=TPropertyValue::ensureBoolean($value);
  777. }
  778. public function getIterator()
  779. {
  780. return new ArrayIterator( $this->_d );
  781. }
  782. public function count()
  783. {
  784. return $this->getCount();
  785. }
  786. public function getCount()
  787. {
  788. return $this->_c;
  789. }
  790. public function itemAt($index)
  791. {
  792. if($index>=0 && $index<$this->_c)
  793. return $this->_d[$index];
  794. else
  795. throw new TInvalidDataValueException('list_index_invalid',$index);
  796. }
  797. public function add($item)
  798. {
  799. $this->insertAt($this->_c,$item);
  800. return $this->_c-1;
  801. }
  802. public function insertAt($index,$item)
  803. {
  804. if(!$this->_r)
  805. {
  806. if($index===$this->_c)
  807. $this->_d[$this->_c++]=$item;
  808. else if($index>=0 && $index<$this->_c)
  809. {
  810. array_splice($this->_d,$index,0,array($item));
  811. $this->_c++;
  812. }
  813. else
  814. throw new TInvalidDataValueException('list_index_invalid',$index);
  815. }
  816. else
  817. throw new TInvalidOperationException('list_readonly',get_class($this));
  818. }
  819. public function remove($item)
  820. {
  821. if(($index=$this->indexOf($item))>=0)
  822. {
  823. $this->removeAt($index);
  824. return $index;
  825. }
  826. else
  827. throw new TInvalidDataValueException('list_item_inexistent');
  828. }
  829. public function removeAt($index)
  830. {
  831. if(!$this->_r)
  832. {
  833. if($index>=0 && $index<$this->_c)
  834. {
  835. $this->_c--;
  836. if($index===$this->_c)
  837. return array_pop($this->_d);
  838. else
  839. {
  840. $item=$this->_d[$index];
  841. array_splice($this->_d,$index,1);
  842. return $item;
  843. }
  844. }
  845. else
  846. throw new TInvalidDataValueException('list_index_invalid',$index);
  847. }
  848. else
  849. throw new TInvalidOperationException('list_readonly',get_class($this));
  850. }
  851. public function clear()
  852. {
  853. for($i=$this->_c-1;$i>=0;--$i)
  854. $this->removeAt($i);
  855. }
  856. public function contains($item)
  857. {
  858. return $this->indexOf($item)>=0;
  859. }
  860. public function indexOf($item)
  861. {
  862. if(($index=array_search($item,$this->_d,true))===false)
  863. return -1;
  864. else
  865. return $index;
  866. }
  867. public function toArray()
  868. {
  869. return $this->_d;
  870. }
  871. public function copyFrom($data)
  872. {
  873. if(is_array($data) || ($data instanceof Traversable))
  874. {
  875. if($this->_c>0)
  876. $this->clear();
  877. foreach($data as $item)
  878. $this->add($item);
  879. }
  880. else if($data!==null)
  881. throw new TInvalidDataTypeException('list_data_not_iterable');
  882. }
  883. public function mergeWith($data)
  884. {
  885. if(is_array($data) || ($data instanceof Traversable))
  886. {
  887. foreach($data as $item)
  888. $this->add($item);
  889. }
  890. else if($data!==null)
  891. throw new TInvalidDataTypeException('list_data_not_iterable');
  892. }
  893. public function offsetExists($offset)
  894. {
  895. return ($offset>=0 && $offset<$this->_c);
  896. }
  897. public function offsetGet($offset)
  898. {
  899. return $this->itemAt($offset);
  900. }
  901. public function offsetSet($offset,$item)
  902. {
  903. if($offset===null || $offset===$this->_c)
  904. $this->insertAt($this->_c,$item);
  905. else
  906. {
  907. $this->removeAt($offset);
  908. $this->insertAt($offset,$item);
  909. }
  910. }
  911. public function offsetUnset($offset)
  912. {
  913. $this->removeAt($offset);
  914. }
  915. }
  916. class TListIterator implements Iterator
  917. {
  918. private $_d;
  919. private $_i;
  920. private $_c;
  921. public function __construct(&$data)
  922. {
  923. $this->_d=&$data;
  924. $this->_i=0;
  925. $this->_c=count($this->_d);
  926. }
  927. public function rewind()
  928. {
  929. $this->_i=0;
  930. }
  931. public function key()
  932. {
  933. return $this->_i;
  934. }
  935. public function current()
  936. {
  937. return $this->_d[$this->_i];
  938. }
  939. public function next()
  940. {
  941. $this->_i++;
  942. }
  943. public function valid()
  944. {
  945. return $this->_i<$this->_c;
  946. }
  947. }
  948. abstract class TCache extends TModule implements ICache, ArrayAccess
  949. {
  950. private $_prefix=null;
  951. private $_primary=true;
  952. public function init($config)
  953. {
  954. if($this->_prefix===null)
  955. $this->_prefix=$this->getApplication()->getUniqueID();
  956. if($this->_primary)
  957. {
  958. if($this->getApplication()->getCache()===null)
  959. $this->getApplication()->setCache($this);
  960. else
  961. throw new TConfigurationException('cache_primary_duplicated',get_class($this));
  962. }
  963. }
  964. public function getPrimaryCache()
  965. {
  966. return $this->_primary;
  967. }
  968. public function setPrimaryCache($value)
  969. {
  970. $this->_primary=TPropertyValue::ensureBoolean($value);
  971. }
  972. public function getKeyPrefix()
  973. {
  974. return $this->_prefix;
  975. }
  976. public function setKeyPrefix($value)
  977. {
  978. $this->_prefix=$value;
  979. }
  980. protected function generateUniqueKey($key)
  981. {
  982. return md5($this->_prefix.$key);
  983. }
  984. public function get($id)
  985. {
  986. if(($value=$this->getValue($this->generateUniqueKey($id)))!==false)
  987. {
  988. $data=unserialize($value);
  989. if(!is_array($data))
  990. return false;
  991. if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
  992. return $data[0];
  993. }
  994. return false;
  995. }
  996. public function set($id,$value,$expire=0,$dependency=null)
  997. {
  998. if(empty($value) && $expire === 0)
  999. $this->delete($id);
  1000. else
  1001. {
  1002. $data=array($value,$dependency);
  1003. return $this->setValue($this->generateUniqueKey($id),serialize($data),$expire);
  1004. }
  1005. }
  1006. public function add($id,$value,$expire=0,$dependency=null)
  1007. {
  1008. if(empty($value) && $expire === 0)
  1009. return false;
  1010. $data=array($value,$dependency);
  1011. return $this->addValue($this->generateUniqueKey($id),serialize($data),$expire);
  1012. }
  1013. public function delete($id)
  1014. {
  1015. return $this->deleteValue($this->generateUniqueKey($id));
  1016. }
  1017. public function flush()
  1018. {
  1019. throw new TNotSupportedException('cache_flush_unsupported');
  1020. }
  1021. abstract protected function getValue($key);
  1022. abstract protected function setValue($key,$value,$expire);
  1023. abstract protected function addValue($key,$value,$expire);
  1024. abstract protected function deleteValue($key);
  1025. public function offsetExists($id)
  1026. {
  1027. return $this->get($id) !== false;
  1028. }
  1029. public function offsetGet($id)
  1030. {
  1031. return $this->get($id);
  1032. }
  1033. public function offsetSet($id, $value)
  1034. {
  1035. $this->set($id, $value);
  1036. }
  1037. public function offsetUnset($id)
  1038. {
  1039. $this->delete($id);
  1040. }
  1041. }
  1042. abstract class TCacheDependency extends TComponent implements ICacheDependency
  1043. {
  1044. }
  1045. class TFileCacheDependency extends TCacheDependency
  1046. {
  1047. private $_fileName;
  1048. private $_timestamp;
  1049. public function __construct($fileName)
  1050. {
  1051. $this->setFileName($fileName);
  1052. }
  1053. public function getFileName()
  1054. {
  1055. return $this->_fileName;
  1056. }
  1057. public function setFileName($value)
  1058. {
  1059. $this->_fileName=$value;
  1060. $this->_timestamp=@filemtime($value);
  1061. }
  1062. public function getTimestamp()
  1063. {
  1064. return $this->_timestamp;
  1065. }
  1066. public function getHasChanged()
  1067. {
  1068. return @filemtime($this->_fileName)!==$this->_timestamp;
  1069. }
  1070. }
  1071. class TDirectoryCacheDependency extends TCacheDependency
  1072. {
  1073. private $_recursiveCheck=true;
  1074. private $_recursiveLevel=-1;
  1075. private $_timestamps;
  1076. private $_directory;
  1077. public function __construct($directory)
  1078. {
  1079. $this->setDirectory($directory);
  1080. }
  1081. public function getDirectory()
  1082. {
  1083. return $this->_directory;
  1084. }
  1085. public function setDirectory($directory)
  1086. {
  1087. if(($path=realpath($directory))===false || !is_dir($path))
  1088. throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
  1089. $this->_directory=$path;
  1090. $this->_timestamps=$this->generateTimestamps($path);
  1091. }
  1092. public function getRecursiveCheck()
  1093. {
  1094. return $this->_recursiveCheck;
  1095. }
  1096. public function setRecursiveCheck($value)
  1097. {
  1098. $this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
  1099. }
  1100. public function getRecursiveLevel()
  1101. {
  1102. return $this->_recursiveLevel;
  1103. }
  1104. public function setRecursiveLevel($value)
  1105. {
  1106. $this->_recursiveLevel=TPropertyValue::ensureInteger($value);
  1107. }
  1108. public function getHasChanged()
  1109. {
  1110. return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
  1111. }
  1112. protected function validateFile($fileName)
  1113. {
  1114. return true;
  1115. }
  1116. protected function validateDirectory($directory)
  1117. {
  1118. return true;
  1119. }
  1120. protected function generateTimestamps($directory,$level=0)
  1121. {
  1122. if(($dir=opendir($directory))===false)
  1123. throw new TIOException('directorycachedependency_directory_invalid',$directory);
  1124. $timestamps=array();
  1125. while(($file=readdir($dir))!==false)
  1126. {
  1127. $path=$directory.DIRECTORY_SEPARATOR.$file;
  1128. if($file==='.' || $file==='..')
  1129. continue;
  1130. else if(is_dir($path))
  1131. {
  1132. if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
  1133. $timestamps=array_merge($this->generateTimestamps($path,$level+1));
  1134. }
  1135. else if($this->validateFile($path))
  1136. $timestamps[$path]=filemtime($path);
  1137. }
  1138. closedir($dir);
  1139. return $timestamps;
  1140. }
  1141. }
  1142. class TGlobalStateCacheDependency extends TCacheDependency
  1143. {
  1144. private $_stateName;
  1145. private $_stateValue;
  1146. public function __construct($name)
  1147. {
  1148. $this->setStateName($name);
  1149. }
  1150. public function getStateName()
  1151. {
  1152. return $this->_stateName;
  1153. }
  1154. public function setStateName($value)
  1155. {
  1156. $this->_stateName=$value;
  1157. $this->_stateValue=Prado::getApplication()->getGlobalState($value);
  1158. }
  1159. public function getHasChanged()
  1160. {
  1161. return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
  1162. }
  1163. }
  1164. class TChainedCacheDependency extends TCacheDependency
  1165. {
  1166. private $_dependencies=null;
  1167. public function getDependencies()
  1168. {
  1169. if($this->_dependencies===null)
  1170. $this->_dependencies=new TCacheDependencyList;
  1171. return $this->_dependencies;
  1172. }
  1173. public function getHasChanged()
  1174. {
  1175. if($this->_dependencies!==null)
  1176. {
  1177. foreach($this->_dependencies as $dependency)
  1178. if($dependency->getHasChanged())
  1179. return true;
  1180. }
  1181. return false;
  1182. }
  1183. }
  1184. class TApplicationStateCacheDependency extends TCacheDependency
  1185. {
  1186. public function getHasChanged()
  1187. {
  1188. return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
  1189. }
  1190. }
  1191. class TCacheDependencyList extends TList
  1192. {
  1193. public function insertAt($index,$item)
  1194. {
  1195. if($item instanceof ICacheDependency)
  1196. parent::insertAt($index,$item);
  1197. else
  1198. throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
  1199. }
  1200. }
  1201. class TTextWriter extends TComponent implements ITextWriter
  1202. {
  1203. private $_str='';
  1204. public function flush()
  1205. {
  1206. $str=$this->_str;
  1207. $this->_str='';
  1208. return $str;
  1209. }
  1210. public function write($str)
  1211. {
  1212. $this->_str.=$str;
  1213. }
  1214. public function writeLine($str='')
  1215. {
  1216. $this->write($str."\n");
  1217. }
  1218. }
  1219. class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable
  1220. {
  1221. private $_d=array();
  1222. private $_r=false;
  1223. public function __construct($data=null,$readOnly=false)
  1224. {
  1225. if($data!==null)
  1226. $this->copyFrom($data);
  1227. $this->setReadOnly($readOnly);
  1228. }
  1229. public function getReadOnly()
  1230. {
  1231. return $this->_r;
  1232. }
  1233. protected function setReadOnly($value)
  1234. {
  1235. $this->_r=TPropertyValue::ensureBoolean($value);
  1236. }
  1237. public function getIterator()
  1238. {
  1239. return new ArrayIterator( $this->_d );
  1240. }
  1241. public function count()
  1242. {
  1243. return $this->getCount();
  1244. }
  1245. public function getCount()
  1246. {
  1247. return count($this->_d);
  1248. }
  1249. public function getKeys()
  1250. {
  1251. return array_keys($this->_d);
  1252. }
  1253. public function itemAt($key)
  1254. {
  1255. return isset($this->_d[$key]) ? $this->_d[$key] : null;
  1256. }
  1257. public function add($key,$value)
  1258. {
  1259. if(!$this->_r)
  1260. $this->_d[$key]=$value;
  1261. else
  1262. throw new TInvalidOperationException('map_readonly',get_class($this));
  1263. }
  1264. public function remove($key)
  1265. {
  1266. if(!$this->_r)
  1267. {
  1268. if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
  1269. {
  1270. $value=$this->_d[$key];
  1271. unset($this->_d[$key]);
  1272. return $value;
  1273. }
  1274. else
  1275. return null;
  1276. }
  1277. else
  1278. throw new TInvalidOperationException('map_readonly',get_class($this));
  1279. }
  1280. public function clear()
  1281. {
  1282. foreach(array_keys($this->_d) as $key)
  1283. $this->remove($key);
  1284. }
  1285. public function contains($key)
  1286. {
  1287. return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
  1288. }
  1289. public function toArray()
  1290. {
  1291. return $this->_d;
  1292. }
  1293. public function copyFrom($data)
  1294. {
  1295. if(is_array($data) || $data instanceof Traversable)
  1296. {
  1297. if($this->getCount()>0)
  1298. $this->clear();
  1299. foreach($data as $key=>$value)
  1300. $this->add($key,$value);
  1301. }
  1302. else if($data!==null)
  1303. throw new TInvalidDataTypeException('map_data_not_iterable');
  1304. }
  1305. public function mergeWith($data)
  1306. {
  1307. if(is_array($data) || $data instanceof Traversable)
  1308. {
  1309. foreach($data as $key=>$value)
  1310. $this->add($key,$value);
  1311. }
  1312. else if($data!==null)
  1313. throw new TInvalidDataTypeException('map_data_not_iterable');
  1314. }
  1315. public function offsetExists($offset)
  1316. {
  1317. return $this->contains($offset);
  1318. }
  1319. public function offsetGet($offset)
  1320. {
  1321. return $this->itemAt($offset);
  1322. }
  1323. public function offsetSet($offset,$item)
  1324. {
  1325. $this->add($offset,$item);
  1326. }
  1327. public function offsetUnset($offset)
  1328. {
  1329. $this->remove($offset);
  1330. }
  1331. }
  1332. class TMapIterator implements Iterator
  1333. {
  1334. private $_d;
  1335. private $_keys;
  1336. private $_key;
  1337. public function __construct(&$data)
  1338. {
  1339. $this->_d=&$data;
  1340. $this->_keys=array_keys($data);
  1341. }
  1342. public function rewind()
  1343. {
  1344. $this->_key=reset($this->_keys);
  1345. }
  1346. public function key()
  1347. {
  1348. return $this->_key;
  1349. }
  1350. public function current()
  1351. {
  1352. return $this->_d[$this->_key];
  1353. }
  1354. public function next()
  1355. {
  1356. $this->_key=next($this->_keys);
  1357. }
  1358. public function valid()
  1359. {
  1360. return $this->_key!==false;
  1361. }
  1362. }
  1363. class TStack extends TComponent implements IteratorAggregate,Countable
  1364. {
  1365. private $_d=array();
  1366. private $_c=0;
  1367. public function __construct($data=null)
  1368. {
  1369. if($data!==null)
  1370. $this->copyFrom($data);
  1371. }
  1372. public function toArray()
  1373. {
  1374. return $this->_d;
  1375. }
  1376. public function copyFrom($data)
  1377. {
  1378. if(is_array($data) || ($data instanceof Traversable))
  1379. {
  1380. $this->clear();
  1381. foreach($data as $item)
  1382. {
  1383. $this->_d[]=$item;
  1384. ++$this->_c;
  1385. }
  1386. }
  1387. else if($data!==null)
  1388. throw new TInvalidDataTypeException('stack_data_not_iterable');
  1389. }
  1390. public function clear()
  1391. {
  1392. $this->_c=0;
  1393. $this->_d=array();
  1394. }
  1395. public function contains($item)
  1396. {
  1397. return array_search($item,$this->_d,true)!==false;
  1398. }
  1399. public function peek()
  1400. {
  1401. if($this->_c===0)
  1402. throw new TInvalidOperationException('stack_empty');
  1403. else
  1404. return $this->_d[$this->_c-1];
  1405. }
  1406. public function pop()
  1407. {
  1408. if($this->_c===0)
  1409. throw new TInvalidOperationException('stack_empty');
  1410. else
  1411. {
  1412. --$this->_c;
  1413. return array_pop($this->_d);
  1414. }
  1415. }
  1416. public function push($item)
  1417. {
  1418. ++$this->_c;
  1419. $this->_d[] = $item;
  1420. }
  1421. public function getIterator()
  1422. {
  1423. return new ArrayIterator( $this->_d );
  1424. }
  1425. public function getCount()
  1426. {
  1427. return $this->_c;
  1428. }
  1429. public function count()
  1430. {
  1431. return $this->getCount();
  1432. }
  1433. }
  1434. class TStackIterator implements Iterator
  1435. {
  1436. private $_d;
  1437. private $_i;
  1438. private $_c;
  1439. public function __construct(&$data)
  1440. {
  1441. $this->_d=&$data;
  1442. $this->_i=0;
  1443. $this->_c=count($this->_d);
  1444. }
  1445. public function rewind()
  1446. {
  1447. $this->_i=0;
  1448. }
  1449. public function key()
  1450. {
  1451. return $this->_i;
  1452. }
  1453. public function current()
  1454. {
  1455. return $this->_d[$this->_i];
  1456. }
  1457. public function next()
  1458. {
  1459. $this->_i++;
  1460. }
  1461. public function valid()
  1462. {
  1463. return $this->_i<$this->_c;
  1464. }
  1465. }
  1466. class TXmlElement extends TComponent
  1467. {
  1468. private $_parent=null;
  1469. private $_tagName='unknown';
  1470. private $_value='';
  1471. private $_elements=null;
  1472. private $_attributes=null;
  1473. public function __construct($tagName)
  1474. {
  1475. $this->setTagName($tagName);
  1476. }
  1477. public function getParent()
  1478. {
  1479. return $this->_parent;
  1480. }
  1481. public function setParent($parent)
  1482. {
  1483. $this->_parent=$parent;
  1484. }
  1485. public function getTagName()
  1486. {
  1487. return $this->_tagName;
  1488. }
  1489. public function setTagName($tagName)
  1490. {
  1491. $this->_tagName=$tagName;
  1492. }
  1493. public function getValue()
  1494. {
  1495. return $this->_value;
  1496. }
  1497. public function setValue($value)
  1498. {
  1499. $this->_value=TPropertyValue::ensureString($value);
  1500. }
  1501. public function getHasElement()
  1502. {
  1503. return $this->_elements!==null && $this->_elements->getCount()>0;
  1504. }
  1505. public function getHasAttribute()
  1506. {
  1507. return $this->_attributes!==null && $this->_attributes->getCount()>0;
  1508. }
  1509. public function getAttribute($name)
  1510. {
  1511. if($this->_attributes!==null)
  1512. return $this->_attributes->itemAt($name);
  1513. else
  1514. return null;
  1515. }
  1516. public function setAttribute($name,$value)
  1517. {
  1518. $this->getAttributes()->add($name,TPropertyValue::ensureString($value));
  1519. }
  1520. public function getElements()
  1521. {
  1522. if(!$this->_elements)
  1523. $this->_elements=new TXmlElementList($this);
  1524. return $this->_elements;
  1525. }
  1526. public function getAttributes()
  1527. {
  1528. if(!$this->_attributes)
  1529. $this->_attributes=new TMap;
  1530. return $this->_attributes;
  1531. }
  1532. public function getElementByTagName($tagName)
  1533. {
  1534. if($this->_elements)
  1535. {
  1536. foreach($this->_elements as $element)
  1537. if($element->_tagName===$tagName)
  1538. return $element;
  1539. }
  1540. return null;
  1541. }
  1542. public function getElementsByTagName($tagName)
  1543. {
  1544. $list=new TList;
  1545. if($this->_elements)
  1546. {
  1547. foreach($this->_elements as $element)
  1548. if($element->_tagName===$tagName)
  1549. $list->add($element);
  1550. }
  1551. return $list;
  1552. }
  1553. public function toString($indent=0)
  1554. {
  1555. $attr='';
  1556. if($this->_attributes!==null)
  1557. {
  1558. foreach($this->_attributes as $name=>$value)
  1559. {
  1560. $value=$this->xmlEncode($value);
  1561. $attr.=" $name=\"$value\"";
  1562. }
  1563. }
  1564. $prefix=str_repeat(' ',$indent*4);
  1565. if($this->getHasElement())
  1566. {
  1567. $str=$prefix."<{$this->_tagName}$attr>\n";
  1568. foreach($this->getElements() as $element)
  1569. $str.=$element->toString($indent+1)."\n";
  1570. $str.=$prefix."</{$this->_tagName}>";
  1571. return $str;
  1572. }
  1573. else if(($value=$this->getValue())!=='')
  1574. {
  1575. $value=$this->xmlEncode($value);
  1576. return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>";
  1577. }
  1578. else
  1579. return $prefix."<{$this->_tagName}$attr />";
  1580. }
  1581. public function __toString()
  1582. {
  1583. return $this->toString();
  1584. }
  1585. private function xmlEncode($str)
  1586. {
  1587. return strtr($str,array(
  1588. '>'=>'&gt;',
  1589. '<'=>'&lt;',
  1590. '&'=>'&amp;',
  1591. '"'=>'&quot;',
  1592. "\r"=>'&#xD;',
  1593. "\t"=>'&#x9;',
  1594. "\n"=>'&#xA;'));
  1595. }
  1596. }
  1597. class TXmlDocument extends TXmlElement
  1598. {
  1599. private $_version;
  1600. private $_encoding;
  1601. public function __construct($version='1.0',$encoding='')
  1602. {
  1603. parent::__construct('');
  1604. $this->setVersion($version);
  1605. $this->setEncoding($encoding);
  1606. }
  1607. public function getVersion()
  1608. {
  1609. return $this->_version;
  1610. }
  1611. public function setVersion($version)
  1612. {
  1613. $this->_version=$version;
  1614. }
  1615. public function getEncoding()
  1616. {
  1617. return $this->_encoding;
  1618. }
  1619. public function setEncoding($encoding)
  1620. {
  1621. $this->_encoding=$encoding;
  1622. }
  1623. public function loadFromFile($file)
  1624. {
  1625. if(($str=@file_get_contents($file))!==false)
  1626. return $this->loadFromString($str);
  1627. else
  1628. throw new TIOException('xmldocument_file_read_failed',$file);
  1629. }
  1630. public function loadFromString($string)
  1631. {
  1632. $doc=new DOMDocument();
  1633. if($doc->loadXML($string)===false)
  1634. return false;
  1635. $this->setEncoding($doc->encoding);
  1636. $this->setVersion($doc->version);
  1637. $element=$doc->documentElement;
  1638. $this->setTagName($element->tagName);
  1639. $this->setValue($element->nodeValue);
  1640. $elements=$this->getElements();
  1641. $attributes=$this->getAttributes();
  1642. $elements->clear();
  1643. $attributes->clear();
  1644. static $bSimpleXml;
  1645. if($bSimpleXml === null)
  1646. $bSimpleXml = (boolean)function_exists('simplexml_load_string');
  1647. if($bSimpleXml)
  1648. {
  1649. $simpleDoc = simplexml_load_string($string);
  1650. $docNamespaces = $simpleDoc->getDocNamespaces(false);
  1651. $simpleDoc = null;
  1652. foreach($docNamespaces as $prefix => $uri)
  1653. {
  1654. if($prefix === '')
  1655. $attributes->add('xmlns', $uri);
  1656. else
  1657. $attributes->add('xmlns:'.$prefix, $uri);
  1658. }
  1659. }
  1660. foreach($element->attributes as $name=>$attr)
  1661. $attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value);
  1662. foreach($element->childNodes as $child)
  1663. {
  1664. if($child instanceof DOMElement)
  1665. $elements->add($this->buildElement($child));
  1666. }
  1667. return true;
  1668. }
  1669. public function saveToFile($file)
  1670. {
  1671. if(($fw=fopen($file,'w'))!==false)
  1672. {
  1673. fwrite($fw,$this->saveToString());
  1674. fclose($fw);
  1675. }
  1676. else
  1677. throw new TIOException('xmldocument_file_write_failed',$file);
  1678. }
  1679. public function saveToString()
  1680. {
  1681. $version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
  1682. $encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
  1683. return "<?xml{$version}{$encoding}?>\n".$this->toString(0);
  1684. }
  1685. public function __toString()
  1686. {
  1687. return $this->saveToString();
  1688. }
  1689. private function buildElement($node)
  1690. {
  1691. $element=new TXmlElement($node->tagName);
  1692. $element->setValue($node->nodeValue);
  1693. foreach($node->attributes as $name=>$attr)
  1694. $element->getAttributes()->add(($attr->prefix === '' ? '' : $attr->prefix . ':') . $name,$attr->value);
  1695. foreach($node->childNodes as $child)
  1696. {
  1697. if($child instanceof DOMElement)
  1698. $element->getElements()->add($this->buildElement($child));
  1699. }
  1700. return $element;
  1701. }
  1702. }
  1703. class TXmlElementList extends TList
  1704. {
  1705. private $_o;
  1706. public function __construct(TXmlElement $owner)
  1707. {
  1708. $this->_o=$owner;
  1709. }
  1710. protected function getOwner()
  1711. {
  1712. return $this->_o;
  1713. }
  1714. public function insertAt($index,$item)
  1715. {
  1716. if($item instanceof TXmlElement)
  1717. {
  1718. parent::insertAt($index,$item);
  1719. if($item->getParent()!==null)
  1720. $item->getParent()->getElements()->remove($item);
  1721. $item->setParent($this->_o);
  1722. }
  1723. else
  1724. throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
  1725. }
  1726. public function removeAt($index)
  1727. {
  1728. $item=parent::removeAt($index);
  1729. if($item instanceof TXmlElement)
  1730. $item->setParent(null);
  1731. return $item;
  1732. }
  1733. }
  1734. class TAuthorizationRule extends TComponent
  1735. {
  1736. private $_action;
  1737. private $_users;
  1738. private $_roles;
  1739. private $_verb;
  1740. private $_ipRules;
  1741. private $_everyone;
  1742. private $_guest;
  1743. private $_authenticated;
  1744. public function __construct($action,$users,$roles,$verb='',$ipRules='')
  1745. {
  1746. $action=strtolower(trim($action));
  1747. if($action==='allow' || $action==='deny')
  1748. $this->_action=$action;
  1749. else
  1750. throw new TInvalidDataValueException('authorizationrule_action_invalid',$action);
  1751. $this->_users=array();
  1752. $this->_roles=array();
  1753. $this->_ipRules=array();
  1754. $this->_everyone=false;
  1755. $this->_guest=false;
  1756. $this->_authenticated=false;
  1757. if(trim($users)==='')
  1758. $users='*';
  1759. foreach(explode(',',$users) as $user)
  1760. {
  1761. if(($user=trim(strtolower($user)))!=='')
  1762. {
  1763. if($user==='*')
  1764. {
  1765. $this->_everyone=true;
  1766. break;
  1767. }
  1768. else if($user==='?')
  1769. $this->_guest=true;
  1770. else if($user==='@')
  1771. $this->_authenticated=true;
  1772. else
  1773. $this->_users[]=$user;
  1774. }
  1775. }
  1776. if(trim($roles)==='')
  1777. $roles='*';
  1778. foreach(explode(',',$roles) as $role)
  1779. {
  1780. if(($role=trim(strtolower($role)))!=='')
  1781. $this->_roles[]=$role;
  1782. }
  1783. if(($verb=trim(strtolower($verb)))==='')
  1784. $verb='*';
  1785. if($verb==='*' || $verb==='get' || $verb==='post')
  1786. $this->_verb=$verb;
  1787. else
  1788. throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb);
  1789. if(trim($ipRules)==='')
  1790. $ipRules='*';
  1791. foreach(explode(',',$ipRules) as $ipRule)
  1792. {
  1793. if(($ipRule=trim($ipRule))!=='')
  1794. $this->_ipRules[]=$ipRule;
  1795. }
  1796. }
  1797. public function getAction()
  1798. {
  1799. return $this->_action;
  1800. }
  1801. public function getUsers()
  1802. {
  1803. return $this->_users;
  1804. }
  1805. public function getRoles()
  1806. {
  1807. return $this->_roles;
  1808. }
  1809. public function getVerb()
  1810. {
  1811. return $this->_verb;
  1812. }
  1813. public function getIPRules()
  1814. {
  1815. return $this->_ipRules;
  1816. }
  1817. public function getGuestApplied()
  1818. {
  1819. return $this->_guest || $this->_everyone;
  1820. }
  1821. public function getEveryoneApplied()
  1822. {
  1823. return $this->_everyone;
  1824. }
  1825. public function getAuthenticatedApplied()
  1826. {
  1827. return $this->_authenticated || $this->_everyone;
  1828. }
  1829. public function isUserAllowed(IUser $user,$verb,$ip)
  1830. {
  1831. if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user))
  1832. return ($this->_action==='allow')?1:-1;
  1833. else
  1834. return 0;
  1835. }
  1836. private function isIpMatched($ip)
  1837. {
  1838. if(empty($this->_ipRules))
  1839. return 1;
  1840. foreach($this->_ipRules as $rule)
  1841. {
  1842. if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0))
  1843. return 1;
  1844. }
  1845. return 0;
  1846. }
  1847. private function isUserMatched($user)
  1848. {
  1849. return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users));
  1850. }
  1851. private function isRoleMatched($user)
  1852. {
  1853. foreach($this->_roles as $role)
  1854. {
  1855. if($role==='*' || $user->isInRole($role))
  1856. return true;
  1857. }
  1858. return false;
  1859. }
  1860. private function isVerbMatched($verb)
  1861. {
  1862. return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0);
  1863. }
  1864. }
  1865. class TAuthorizationRuleCollection extends TList
  1866. {
  1867. public function isUserAllowed($user,$verb,$ip)
  1868. {
  1869. if($user instanceof IUser)
  1870. {
  1871. $verb=strtolower(trim($verb));
  1872. foreach($this as $rule)
  1873. {
  1874. if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0)
  1875. return ($decision>0);
  1876. }
  1877. return true;
  1878. }
  1879. else
  1880. return false;
  1881. }
  1882. public function insertAt($index,$item)
  1883. {
  1884. if($item instanceof TAuthorizationRule)
  1885. parent::insertAt($index,$item);
  1886. else
  1887. throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required');
  1888. }
  1889. }
  1890. class TSecurityManager extends TModule
  1891. {
  1892. const STATE_VALIDATION_KEY = 'prado:securitymanager:validationkey';
  1893. const STATE_ENCRYPTION_KEY = 'prado:securitymanager:encryptionkey';
  1894. private $_validationKey = null;
  1895. private $_encryptionKey = null;
  1896. private $_validation = TSecurityManagerValidationMode::SHA1;
  1897. private $_encryption = '3DES';
  1898. public function init($config)
  1899. {
  1900. $this->getApplication()->setSecurityManager($this);
  1901. }
  1902. protected function generateRandomKey()
  1903. {
  1904. return rand().rand().rand().rand();
  1905. }
  1906. public function getValidationKey()
  1907. {
  1908. if(null === $this->_validationKey) {
  1909. if(null === ($this->_validationKey = $this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))) {
  1910. $this->_validationKey = $this->generateRandomKey();
  1911. $this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY, $this->_validationKey, null);
  1912. }
  1913. }
  1914. return $this->_validationKey;
  1915. }
  1916. public function setValidationKey($value)
  1917. {
  1918. if('' === $value)
  1919. throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
  1920. $this->_validationKey = $value;
  1921. }
  1922. public function getEncryptionKey()
  1923. {
  1924. if(null === $this->_encryptionKey) {
  1925. if(null === ($this->_encryptionKey = $this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))) {
  1926. $this->_encryptionKey = $this->generateRandomKey();
  1927. $this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY, $this->_encryptionKey, null);
  1928. }
  1929. }
  1930. return $this->_encryptionKey;
  1931. }
  1932. public function setEncryptionKey($value)
  1933. {
  1934. if('' === $value)
  1935. throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
  1936. $this->_encryptionKey = $value;
  1937. }
  1938. public function getValidation()
  1939. {
  1940. return $this->_validation;
  1941. }
  1942. public function setValidation($value)
  1943. {
  1944. $this->_validation = TPropertyValue::ensureEnum($value, 'TSecurityManagerValidationMode');
  1945. }
  1946. public function getEncryption()
  1947. {
  1948. return $this->_encryption;
  1949. }
  1950. public function setEncryption($value)
  1951. {
  1952. throw new TNotSupportedException('Currently only 3DES encryption is supported');
  1953. }
  1954. public function encrypt($data)
  1955. {
  1956. if(!function_exists('mcrypt_encrypt'))
  1957. throw new TNotSupportedException('securitymanager_mcryptextension_required');
  1958. $module = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
  1959. $key = substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
  1960. srand();
  1961. $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
  1962. mcrypt_generic_init($module, $key, $iv);
  1963. $encrypted = $iv.mcrypt_generic($module, $data);
  1964. mcrypt_generic_deinit($module);
  1965. mcrypt_module_close($module);
  1966. return $encrypted;
  1967. }
  1968. public function decrypt($data)
  1969. {
  1970. if(!function_exists('mcrypt_decrypt'))
  1971. throw new TNotSupportedException('securitymanager_mcryptextension_required');
  1972. $module = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
  1973. $key = substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
  1974. $ivSize = mcrypt_enc_get_iv_size($module);
  1975. $iv = substr($data, 0, $ivSize);
  1976. mcrypt_generic_init($module, $key, $iv);
  1977. $decrypted = mdecrypt_generic($module, substr($data, $ivSize));
  1978. mcrypt_generic_deinit($module);
  1979. mcrypt_module_close($module);
  1980. return $decrypted;
  1981. }
  1982. public function hashData($data)
  1983. {
  1984. $hmac = $this->computeHMAC($data);
  1985. return $hmac.$data;
  1986. }
  1987. public function validateData($data)
  1988. {
  1989. $len = 'SHA1' === $this->_validation ? 40 : 32;
  1990. if(strlen($data) < $len)
  1991. return false;
  1992. $hmac = substr($data, 0, $len);
  1993. $data2 = substr($data, $len);
  1994. return $hmac === $this->computeHMAC($data2) ? $data2 : false;
  1995. }
  1996. protected function computeHMAC($data)
  1997. {
  1998. if('SHA1' === $this->_validation) {
  1999. $pack = 'H40';
  2000. $func = 'sha1';
  2001. } else {
  2002. $pack = 'H32';
  2003. $func = 'md5';
  2004. }
  2005. $key = $this->getValidationKey();
  2006. $key = str_pad($func($key), 64, chr(0));
  2007. return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
  2008. }
  2009. }
  2010. class TSecurityManagerValidationMode extends TEnumerable
  2011. {
  2012. const MD5 = 'MD5';
  2013. const SHA1 = 'SHA1';
  2014. }
  2015. class THttpUtility
  2016. {
  2017. private static $_encodeTable=array('<'=>'&lt;','>'=>'&gt;','"'=>'&quot;');
  2018. private static $_decodeTable=array('&lt;'=>'<','&gt;'=>'>','&quot;'=>'"');
  2019. public static function htmlEncode($s)
  2020. {
  2021. return strtr($s,self::$_encodeTable);
  2022. }
  2023. public static function htmlDecode($s)
  2024. {
  2025. return strtr($s,self::$_decodeTable);
  2026. }
  2027. }
  2028. class TJavaScript
  2029. {
  2030. private static $_json;
  2031. public static function renderScriptFiles($files)
  2032. {
  2033. $str='';
  2034. foreach($files as $file)
  2035. $str.= self::renderScriptFile($file);
  2036. return $str;
  2037. }
  2038. public static function renderScriptFile($file)
  2039. {
  2040. return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
  2041. }
  2042. public static function renderScriptBlocks($scripts)
  2043. {
  2044. if(count($scripts))
  2045. return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
  2046. else
  2047. return '';
  2048. }
  2049. public static function renderScriptBlock($script)
  2050. {
  2051. return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
  2052. }
  2053. public static function quoteString($js,$forUrl=false)
  2054. {
  2055. if($forUrl)
  2056. return strtr($js,array('%'=>'%25',"\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
  2057. else
  2058. return strtr($js,array("\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
  2059. }
  2060. public static function quoteFunction($js)
  2061. {
  2062. if(self::isFunction($js))
  2063. return $js;
  2064. else
  2065. return 'javascript:'.$js;
  2066. }
  2067. public static function isFunction($js)
  2068. {
  2069. return preg_match('/^\s*javascript:/i', $js);
  2070. }
  2071. public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
  2072. {
  2073. if(is_string($value))
  2074. {
  2075. if(($n=strlen($value))>2)
  2076. {
  2077. $first=$value[0];
  2078. $last=$value[$n-1];
  2079. if(($first==='[' && $last===']') || ($first==='{' && $last==='}'))
  2080. return $value;
  2081. }
  2082. if(self::isFunction($value))
  2083. return preg_replace('/^\s*javascript:/', '', $value);
  2084. else
  2085. return "'".self::quoteString($value)."'";
  2086. }
  2087. else if(is_bool($value))
  2088. return $value?'true':'false';
  2089. else if(is_array($value))
  2090. {
  2091. $results='';
  2092. if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
  2093. {
  2094. foreach($value as $k=>$v)
  2095. {
  2096. if($v!=='' || $encodeEmptyStrings)
  2097. {
  2098. if($results!=='')
  2099. $results.=',';
  2100. $results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings);
  2101. }
  2102. }
  2103. return '{'.$results.'}';
  2104. }
  2105. else
  2106. {
  2107. foreach($value as $v)
  2108. {
  2109. if($v!=='' || $encodeEmptyStrings)
  2110. {
  2111. if($results!=='')
  2112. $results.=',';
  2113. $results.=self::encode($v,$toMap, $encodeEmptyStrings);
  2114. }
  2115. }
  2116. return '['.$results.']';
  2117. }
  2118. }
  2119. else if(is_integer($value))
  2120. return "$value";
  2121. else if(is_float($value))
  2122. {
  2123. if($value===-INF)
  2124. return 'Number.NEGATIVE_INFINITY';
  2125. else if($value===INF)
  2126. return 'Number.POSITIVE_INFINITY';
  2127. else
  2128. return "$value";
  2129. }
  2130. else if(is_object($value))
  2131. return self::encode(get_object_vars($value),$toMap);
  2132. else if($value===null)
  2133. return 'null';
  2134. else
  2135. return '';
  2136. }
  2137. public static function jsonEncode($value)
  2138. {
  2139. if(self::$_json === null)
  2140. self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON');
  2141. return self::$_json->encode($value);
  2142. }
  2143. public static function jsonDecode($value)
  2144. {
  2145. if(self::$_json === null)
  2146. self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON');
  2147. return self::$_json->decode($value);
  2148. }
  2149. }
  2150. class TUrlManager extends TModule
  2151. {
  2152. public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
  2153. {
  2154. $url=$serviceID.'='.urlencode($serviceParam);
  2155. $amp=$encodeAmpersand?'&amp;':'&';
  2156. $request=$this->getRequest();
  2157. if(is_array($getItems) || $getItems instanceof Traversable)
  2158. {
  2159. if($encodeGetItems)
  2160. {
  2161. foreach($getItems as $name=>$value)
  2162. {
  2163. if(is_array($value))
  2164. {
  2165. $name=urlencode($name.'[]');
  2166. foreach($value as $v)
  2167. $url.=$amp.$name.'='.urlencode($v);
  2168. }
  2169. else
  2170. $url.=$amp.urlencode($name).'='.urlencode($value);
  2171. }
  2172. }
  2173. else
  2174. {
  2175. foreach($getItems as $name=>$value)
  2176. {
  2177. if(is_array($value))
  2178. {
  2179. foreach($value as $v)
  2180. $url.=$amp.$name.'[]='.$v;
  2181. }
  2182. else
  2183. $url.=$amp.$name.'='.$value;
  2184. }
  2185. }
  2186. }
  2187. if($request->getUrlFormat()===THttpRequestUrlFormat::Path)
  2188. return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
  2189. else
  2190. return $request->getApplicationUrl().'?'.$url;
  2191. }
  2192. public function parseUrl()
  2193. {
  2194. $request=$this->getRequest();
  2195. $pathInfo=trim($request->getPathInfo(),'/');
  2196. if($request->getUrlFormat()===THttpRequestUrlFormat::Path && $pathInfo!=='')
  2197. {
  2198. $separator=$request->getUrlParamSeparator();
  2199. $paths=explode('/',$pathInfo);
  2200. $getVariables=array();
  2201. foreach($paths as $path)
  2202. {
  2203. if(($path=trim($path))!=='')
  2204. {
  2205. if(($pos=strpos($path,$separator))!==false)
  2206. {
  2207. $name=substr($path,0,$pos);
  2208. $value=substr($path,$pos+1);
  2209. if(($pos=strpos($name,'[]'))!==false)
  2210. $getVariables[substr($name,0,$pos)][]=$value;
  2211. else
  2212. $getVariables[$name]=$value;
  2213. }
  2214. else
  2215. $getVariables[$path]='';
  2216. }
  2217. }
  2218. return $getVariables;
  2219. }
  2220. else
  2221. return array();
  2222. }
  2223. }
  2224. class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
  2225. {
  2226. const CGIFIX__PATH_INFO = 1;
  2227. const CGIFIX__SCRIPT_NAME = 2;
  2228. private $_urlManager=null;
  2229. private $_urlManagerID='';
  2230. private $_separator=',';
  2231. private $_serviceID=null;
  2232. private $_serviceParam=null;
  2233. private $_cookies=null;
  2234. private $_requestUri;
  2235. private $_pathInfo;
  2236. private $_cookieOnly=null;
  2237. private $_urlFormat=THttpRequestUrlFormat::Get;
  2238. private $_services;
  2239. private $_requestResolved=false;
  2240. private $_enableCookieValidation=false;
  2241. private $_cgiFix=0;
  2242. private $_url=null;
  2243. private $_id;
  2244. private $_items=array();
  2245. public function getID()
  2246. {
  2247. return $this->_id;
  2248. }
  2249. public function setID($value)
  2250. {
  2251. $this->_id=$value;
  2252. }
  2253. public function init($config)
  2254. {
  2255. if(empty($this->_urlManagerID))
  2256. {
  2257. $this->_urlManager=new TUrlManager;
  2258. $this->_urlManager->init(null);
  2259. }
  2260. else
  2261. {
  2262. $this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
  2263. if($this->_urlManager===null)
  2264. throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
  2265. if(!($this->_urlManager instanceof TUrlManager))
  2266. throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
  2267. }
  2268. if(php_sapi_name()==='cli')
  2269. {
  2270. $_SERVER['REMOTE_ADDR']='127.0.0.1';
  2271. $_SERVER['REQUEST_METHOD']='GET';
  2272. $_SERVER['SERVER_NAME']='localhost';
  2273. $_SERVER['SERVER_PORT']=80;
  2274. $_SERVER['HTTP_USER_AGENT']='';
  2275. }
  2276. if(isset($_SERVER['REQUEST_URI']))
  2277. $this->_requestUri=$_SERVER['REQUEST_URI'];
  2278. else $this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
  2279. if($this->_cgiFix&self::CGIFIX__PATH_INFO && isset($_SERVER['ORIG_PATH_INFO']))
  2280. $this->_pathInfo=substr($_SERVER['ORIG_PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
  2281. elseif(isset($_SERVER['PATH_INFO']))
  2282. $this->_pathInfo=$_SERVER['PATH_INFO'];
  2283. else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
  2284. $this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
  2285. else
  2286. $this->_pathInfo='';
  2287. if(get_magic_quotes_gpc())
  2288. {
  2289. if(isset($_GET))
  2290. $_GET=$this->stripSlashes($_GET);
  2291. if(isset($_POST))
  2292. $_POST=$this->stripSlashes($_POST);
  2293. if(isset($_REQUEST))
  2294. $_REQUEST=$this->stripSlashes($_REQUEST);
  2295. if(isset($_COOKIE))
  2296. $_COOKIE=$this->stripSlashes($_COOKIE);
  2297. }
  2298. $this->getApplication()->setRequest($this);
  2299. }
  2300. public function stripSlashes(&$data)
  2301. {
  2302. return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
  2303. }
  2304. public function getUrl()
  2305. {
  2306. if($this->_url===null)
  2307. {
  2308. $secure=$this->getIsSecureConnection();
  2309. $url=$secure?'https://':'http://';
  2310. if(empty($_SERVER['HTTP_HOST']))
  2311. {
  2312. $url.=$_SERVER['SERVER_NAME'];
  2313. $port=$_SERVER['SERVER_PORT'];
  2314. if(($port!=80 && !$secure) || ($port!=443 && $secure))
  2315. $url.=':'.$port;
  2316. }
  2317. else
  2318. $url.=$_SERVER['HTTP_HOST'];
  2319. $url.=$this->getRequestUri();
  2320. $this->_url=new TUri($url);
  2321. }
  2322. return $this->_url;
  2323. }
  2324. public function getUrlManager()
  2325. {
  2326. return $this->_urlManagerID;
  2327. }
  2328. public function setUrlManager($value)
  2329. {
  2330. $this->_urlManagerID=$value;
  2331. }
  2332. public function getUrlManagerModule()
  2333. {
  2334. return $this->_urlManager;
  2335. }
  2336. public function getUrlFormat()
  2337. {
  2338. return $this->_urlFormat;
  2339. }
  2340. public function setUrlFormat($value)
  2341. {
  2342. $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
  2343. }
  2344. public function getUrlParamSeparator()
  2345. {
  2346. return $this->_separator;
  2347. }
  2348. public function setUrlParamSeparator($value)
  2349. {
  2350. if(strlen($value)===1)
  2351. $this->_separator=$value;
  2352. else
  2353. throw new TInvalidDataValueException('httprequest_separator_invalid');
  2354. }
  2355. public function getRequestType()
  2356. {
  2357. return $_SERVER['REQUEST_METHOD'];
  2358. }
  2359. public function getIsSecureConnection()
  2360. {
  2361. return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
  2362. }
  2363. public function getPathInfo()
  2364. {
  2365. return $this->_pathInfo;
  2366. }
  2367. public function setPathInfo($value)
  2368. {
  2369. $this->_pathInfo = $value;
  2370. }
  2371. public function getQueryString()
  2372. {
  2373. return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:'';
  2374. }
  2375. public function getHttpProtocolVersion ()
  2376. {
  2377. return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:'';
  2378. }
  2379. public function getRequestUri()
  2380. {
  2381. return $this->_requestUri;
  2382. }
  2383. public function getBaseUrl($forceSecureConnection=false)
  2384. {
  2385. $url=$this->getUrl();
  2386. $scheme=($forceSecureConnection)?"https":$url->getScheme();
  2387. $host=$url->getHost();
  2388. if (($port=$url->getPort())) $host.=':'.$port;
  2389. return $scheme.'://'.$host;
  2390. }
  2391. public function getApplicationUrl()
  2392. {
  2393. if($this->_cgiFix&self::CGIFIX__SCRIPT_NAME && isset($_SERVER['ORIG_SCRIPT_NAME']))
  2394. return $_SERVER['ORIG_SCRIPT_NAME'];
  2395. return $_SERVER['SCRIPT_NAME'];
  2396. }
  2397. public function getAbsoluteApplicationUrl($forceSecureConnection=false)
  2398. {
  2399. return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
  2400. }
  2401. public function getApplicationFilePath()
  2402. {
  2403. return realpath($_SERVER['SCRIPT_FILENAME']);
  2404. }
  2405. public function getServerName()
  2406. {
  2407. return $_SERVER['SERVER_NAME'];
  2408. }
  2409. public function getServerPort()
  2410. {
  2411. return $_SERVER['SERVER_PORT'];
  2412. }
  2413. public function getUrlReferrer()
  2414. {
  2415. return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
  2416. }
  2417. public function getBrowser()
  2418. {
  2419. try
  2420. {
  2421. return get_browser();
  2422. }
  2423. catch(TPhpErrorException $e)
  2424. {
  2425. throw new TConfigurationException('httprequest_browscap_required');
  2426. }
  2427. }
  2428. public function getUserAgent()
  2429. {
  2430. return $_SERVER['HTTP_USER_AGENT'];
  2431. }
  2432. public function getUserHostAddress()
  2433. {
  2434. return $_SERVER['REMOTE_ADDR'];
  2435. }
  2436. public function getUserHost()
  2437. {
  2438. return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
  2439. }
  2440. public function getAcceptTypes()
  2441. {
  2442. return $_SERVER['HTTP_ACCEPT'];
  2443. }
  2444. public function getUserLanguages()
  2445. {
  2446. return Prado::getUserLanguages();
  2447. }
  2448. public function getEnableCookieValidation()
  2449. {
  2450. return $this->_enableCookieValidation;
  2451. }
  2452. public function setEnableCookieValidation($value)
  2453. {
  2454. $this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
  2455. }
  2456. public function getCgiFix()
  2457. {
  2458. return $this->_cgiFix;
  2459. }
  2460. public function setCgiFix($value)
  2461. {
  2462. $this->_cgiFix=TPropertyValue::ensureInteger($value);
  2463. }
  2464. public function getCookies()
  2465. {
  2466. if($this->_cookies===null)
  2467. {
  2468. $this->_cookies=new THttpCookieCollection;
  2469. if($this->getEnableCookieValidation())
  2470. {
  2471. $sm=$this->getApplication()->getSecurityManager();
  2472. foreach($_COOKIE as $key=>$value)
  2473. {
  2474. if(($value=$sm->validateData($value))!==false)
  2475. $this->_cookies->add(new THttpCookie($key,$value));
  2476. }
  2477. }
  2478. else
  2479. {
  2480. foreach($_COOKIE as $key=>$value)
  2481. $this->_cookies->add(new THttpCookie($key,$value));
  2482. }
  2483. }
  2484. return $this->_cookies;
  2485. }
  2486. public function getUploadedFiles()
  2487. {
  2488. return $_FILES;
  2489. }
  2490. public function getServerVariables()
  2491. {
  2492. return $_SERVER;
  2493. }
  2494. public function getEnvironmentVariables()
  2495. {
  2496. return $_ENV;
  2497. }
  2498. public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
  2499. {
  2500. if ($this->_cookieOnly===null)
  2501. $this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
  2502. $url=$this->_urlManager->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
  2503. if(defined('SID') && SID != '' && !$this->_cookieOnly)
  2504. return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&amp;':'&')) . SID;
  2505. else
  2506. return $url;
  2507. }
  2508. protected function parseUrl()
  2509. {
  2510. return $this->_urlManager->parseUrl();
  2511. }
  2512. public function resolveRequest($serviceIDs)
  2513. {
  2514. $getParams=$this->parseUrl();
  2515. foreach($getParams as $name=>$value)
  2516. $_GET[$name]=$value;
  2517. $this->_items=array_merge($_GET,$_POST);
  2518. $this->_requestResolved=true;
  2519. foreach($serviceIDs as $serviceID)
  2520. {
  2521. if($this->contains($serviceID))
  2522. {
  2523. $this->setServiceID($serviceID);
  2524. $this->setServiceParameter($this->itemAt($serviceID));
  2525. return $serviceID;
  2526. }
  2527. }
  2528. return null;
  2529. }
  2530. public function getRequestResolved()
  2531. {
  2532. return $this->_requestResolved;
  2533. }
  2534. public function getServiceID()
  2535. {
  2536. return $this->_serviceID;
  2537. }
  2538. public function setServiceID($value)
  2539. {
  2540. $this->_serviceID=$value;
  2541. }
  2542. public function getServiceParameter()
  2543. {
  2544. return $this->_serviceParam;
  2545. }
  2546. public function setServiceParameter($value)
  2547. {
  2548. $this->_serviceParam=$value;
  2549. }
  2550. public function getIterator()
  2551. {
  2552. return new TMapIterator($this->_items);
  2553. }
  2554. public function getCount()
  2555. {
  2556. return count($this->_items);
  2557. }
  2558. public function count()
  2559. {
  2560. return $this->getCount();
  2561. }
  2562. public function getKeys()
  2563. {
  2564. return array_keys($this->_items);
  2565. }
  2566. public function itemAt($key)
  2567. {
  2568. return isset($this->_items[$key]) ? $this->_items[$key] : null;
  2569. }
  2570. public function add($key,$value)
  2571. {
  2572. $this->_items[$key]=$value;
  2573. }
  2574. public function remove($key)
  2575. {
  2576. if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
  2577. {
  2578. $value=$this->_items[$key];
  2579. unset($this->_items[$key]);
  2580. return $value;
  2581. }
  2582. else
  2583. return null;
  2584. }
  2585. public function clear()
  2586. {
  2587. foreach(array_keys($this->_items) as $key)
  2588. $this->remove($key);
  2589. }
  2590. public function contains($key)
  2591. {
  2592. return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
  2593. }
  2594. public function toArray()
  2595. {
  2596. return $this->_items;
  2597. }
  2598. public function offsetExists($offset)
  2599. {
  2600. return $this->contains($offset);
  2601. }
  2602. public function offsetGet($offset)
  2603. {
  2604. return $this->itemAt($offset);
  2605. }
  2606. public function offsetSet($offset,$item)
  2607. {
  2608. $this->add($offset,$item);
  2609. }
  2610. public function offsetUnset($offset)
  2611. {
  2612. $this->remove($offset);
  2613. }
  2614. }
  2615. class THttpCookieCollection extends TList
  2616. {
  2617. private $_o;
  2618. public function __construct($owner=null)
  2619. {
  2620. $this->_o=$owner;
  2621. }
  2622. public function insertAt($index,$item)
  2623. {
  2624. if($item instanceof THttpCookie)
  2625. {
  2626. parent::insertAt($index,$item);
  2627. if($this->_o instanceof THttpResponse)
  2628. $this->_o->addCookie($item);
  2629. }
  2630. else
  2631. throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
  2632. }
  2633. public function removeAt($index)
  2634. {
  2635. $item=parent::removeAt($index);
  2636. if($this->_o instanceof THttpResponse)
  2637. $this->_o->removeCookie($item);
  2638. return $item;
  2639. }
  2640. public function itemAt($index)
  2641. {
  2642. if(is_integer($index))
  2643. return parent::itemAt($index);
  2644. else
  2645. return $this->findCookieByName($index);
  2646. }
  2647. public function findCookieByName($name)
  2648. {
  2649. foreach($this as $cookie)
  2650. if($cookie->getName()===$name)
  2651. return $cookie;
  2652. return null;
  2653. }
  2654. }
  2655. class THttpCookie extends TComponent
  2656. {
  2657. private $_domain='';
  2658. private $_name;
  2659. private $_value='';
  2660. private $_expire=0;
  2661. private $_path='/';
  2662. private $_secure=false;
  2663. private $_httpOnly=false;
  2664. public function __construct($name,$value)
  2665. {
  2666. $this->_name=$name;
  2667. $this->_value=$value;
  2668. }
  2669. public function getDomain()
  2670. {
  2671. return $this->_domain;
  2672. }
  2673. public function setDomain($value)
  2674. {
  2675. $this->_domain=$value;
  2676. }
  2677. public function getExpire()
  2678. {
  2679. return $this->_expire;
  2680. }
  2681. public function setExpire($value)
  2682. {
  2683. $this->_expire=TPropertyValue::ensureInteger($value);
  2684. }
  2685. public function getHttpOnly()
  2686. {
  2687. return $this->_httpOnly;
  2688. }
  2689. public function setHttpOnly($value)
  2690. {
  2691. $this->_httpOnly = TPropertyValue::ensureBoolean($value);
  2692. }
  2693. public function getName()
  2694. {
  2695. return $this->_name;
  2696. }
  2697. public function setName($value)
  2698. {
  2699. $this->_name=$value;
  2700. }
  2701. public function getValue()
  2702. {
  2703. return $this->_value;
  2704. }
  2705. public function setValue($value)
  2706. {
  2707. $this->_value=$value;
  2708. }
  2709. public function getPath()
  2710. {
  2711. return $this->_path;
  2712. }
  2713. public function setPath($value)
  2714. {
  2715. $this->_path=$value;
  2716. }
  2717. public function getSecure()
  2718. {
  2719. return $this->_secure;
  2720. }
  2721. public function setSecure($value)
  2722. {
  2723. $this->_secure=TPropertyValue::ensureBoolean($value);
  2724. }
  2725. }
  2726. class TUri extends TComponent
  2727. {
  2728. private static $_defaultPort=array(
  2729. 'ftp'=>21,
  2730. 'gopher'=>70,
  2731. 'http'=>80,
  2732. 'https'=>443,
  2733. 'news'=>119,
  2734. 'nntp'=>119,
  2735. 'wais'=>210,
  2736. 'telnet'=>23
  2737. );
  2738. private $_scheme;
  2739. private $_host;
  2740. private $_port;
  2741. private $_user;
  2742. private $_pass;
  2743. private $_path;
  2744. private $_query;
  2745. private $_fragment;
  2746. private $_uri;
  2747. public function __construct($uri)
  2748. {
  2749. if(($ret=@parse_url($uri))!==false)
  2750. {
  2751. $this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
  2752. $this->_host=isset($ret['host'])?$ret['host']:'';
  2753. $this->_port=isset($ret['port'])?$ret['port']:'';
  2754. $this->_user=isset($ret['user'])?$ret['user']:'';
  2755. $this->_pass=isset($ret['pass'])?$ret['pass']:'';
  2756. $this->_path=isset($ret['path'])?$ret['path']:'';
  2757. $this->_query=isset($ret['query'])?$ret['query']:'';
  2758. $this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
  2759. $this->_uri=$uri;
  2760. }
  2761. else
  2762. {
  2763. throw new TInvalidDataValueException('uri_format_invalid',$uri);
  2764. }
  2765. }
  2766. public function getUri()
  2767. {
  2768. return $this->_uri;
  2769. }
  2770. public function getScheme()
  2771. {
  2772. return $this->_scheme;
  2773. }
  2774. public function getHost()
  2775. {
  2776. return $this->_host;
  2777. }
  2778. public function getPort()
  2779. {
  2780. return $this->_port;
  2781. }
  2782. public function getUser()
  2783. {
  2784. return $this->_user;
  2785. }
  2786. public function getPassword()
  2787. {
  2788. return $this->_pass;
  2789. }
  2790. public function getPath()
  2791. {
  2792. return $this->_path;
  2793. }
  2794. public function getQuery()
  2795. {
  2796. return $this->_query;
  2797. }
  2798. public function getFragment()
  2799. {
  2800. return $this->_fragment;
  2801. }
  2802. }
  2803. class THttpRequestUrlFormat extends TEnumerable
  2804. {
  2805. const Get='Get';
  2806. const Path='Path';
  2807. }
  2808. class THttpResponseAdapter extends TApplicationComponent
  2809. {
  2810. private $_response;
  2811. public function __construct($response)
  2812. {
  2813. $this->_response=$response;
  2814. }
  2815. public function getResponse()
  2816. {
  2817. return $this->_response;
  2818. }
  2819. public function flushContent()
  2820. {
  2821. $this->_response->flushContent();
  2822. }
  2823. public function httpRedirect($url)
  2824. {
  2825. $this->_response->httpRedirect($url);
  2826. }
  2827. public function createNewHtmlWriter($type, $writer)
  2828. {
  2829. return $this->_response->createNewHtmlWriter($type,$writer);
  2830. }
  2831. }
  2832. class THttpResponse extends TModule implements ITextWriter
  2833. {
  2834. const DEFAULT_CONTENTTYPE = 'text/html';
  2835. const DEFAULT_CHARSET = 'UTF-8';
  2836. private static $HTTP_STATUS_CODES = array(
  2837. 100 => 'Continue', 101 => 'Switching Protocols',
  2838. 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
  2839. 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
  2840. 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',
  2841. 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
  2842. );
  2843. private $_bufferOutput=true;
  2844. private $_initialized=false;
  2845. private $_cookies=null;
  2846. private $_status=200;
  2847. private $_reason='OK';
  2848. private $_htmlWriterType='System.Web.UI.THtmlWriter';
  2849. private $_contentType=null;
  2850. private $_charset='';
  2851. private $_adapter;
  2852. public function __destruct()
  2853. {
  2854. }
  2855. public function setAdapter(THttpResponseAdapter $adapter)
  2856. {
  2857. $this->_adapter=$adapter;
  2858. }
  2859. public function getAdapter()
  2860. {
  2861. return $this->_adapter;
  2862. }
  2863. public function getHasAdapter()
  2864. {
  2865. return $this->_adapter!==null;
  2866. }
  2867. public function init($config)
  2868. {
  2869. if($this->_bufferOutput)
  2870. ob_start();
  2871. $this->_initialized=true;
  2872. $this->getApplication()->setResponse($this);
  2873. }
  2874. public function getCacheExpire()
  2875. {
  2876. return session_cache_expire();
  2877. }
  2878. public function setCacheExpire($value)
  2879. {
  2880. session_cache_expire(TPropertyValue::ensureInteger($value));
  2881. }
  2882. public function getCacheControl()
  2883. {
  2884. return session_cache_limiter();
  2885. }
  2886. public function setCacheControl($value)
  2887. {
  2888. session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
  2889. }
  2890. public function setContentType($type)
  2891. {
  2892. $this->_contentType = $type;
  2893. }
  2894. public function getContentType()
  2895. {
  2896. return $this->_contentType;
  2897. }
  2898. public function getCharset()
  2899. {
  2900. return $this->_charset;
  2901. }
  2902. public function setCharset($charset)
  2903. {
  2904. $this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
  2905. }
  2906. public function getBufferOutput()
  2907. {
  2908. return $this->_bufferOutput;
  2909. }
  2910. public function setBufferOutput($value)
  2911. {
  2912. if($this->_initialized)
  2913. throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
  2914. else
  2915. $this->_bufferOutput=TPropertyValue::ensureBoolean($value);
  2916. }
  2917. public function getStatusCode()
  2918. {
  2919. return $this->_status;
  2920. }
  2921. public function setStatusCode($status, $reason=null)
  2922. {
  2923. $status=TPropertyValue::ensureInteger($status);
  2924. if(isset(self::$HTTP_STATUS_CODES[$status])) {
  2925. $this->_reason=self::$HTTP_STATUS_CODES[$status];
  2926. }else{
  2927. if($reason===null || $reason==='') {
  2928. throw new TInvalidDataValueException("response_status_reason_missing");
  2929. }
  2930. $reason=TPropertyValue::ensureString($reason);
  2931. if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
  2932. throw new TInvalidDataValueException("response_status_reason_barchars");
  2933. }
  2934. $this->_reason=$reason;
  2935. }
  2936. $this->_status=$status;
  2937. }
  2938. public function getStatusReason() {
  2939. return $this->_reason;
  2940. }
  2941. public function getCookies()
  2942. {
  2943. if($this->_cookies===null)
  2944. $this->_cookies=new THttpCookieCollection($this);
  2945. return $this->_cookies;
  2946. }
  2947. public function write($str)
  2948. {
  2949. echo $str;
  2950. }
  2951. public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
  2952. {
  2953. static $defaultMimeTypes=array(
  2954. 'css'=>'text/css',
  2955. 'gif'=>'image/gif',
  2956. 'png'=>'image/png',
  2957. 'jpg'=>'image/jpeg',
  2958. 'jpeg'=>'image/jpeg',
  2959. 'htm'=>'text/html',
  2960. 'html'=>'text/html',
  2961. 'js'=>'javascript/js',
  2962. 'pdf'=>'application/pdf',
  2963. 'xls'=>'application/vnd.ms-excel',
  2964. );
  2965. if($mimeType===null)
  2966. {
  2967. $mimeType='text/plain';
  2968. if(function_exists('mime_content_type'))
  2969. $mimeType=mime_content_type($fileName);
  2970. else if(($ext=strrchr($fileName,'.'))!==false)
  2971. {
  2972. $ext=substr($ext,1);
  2973. if(isset($defaultMimeTypes[$ext]))
  2974. $mimeType=$defaultMimeTypes[$ext];
  2975. }
  2976. }
  2977. if($clientFileName===null)
  2978. $clientFileName=basename($fileName);
  2979. else
  2980. $clientFileName=basename($clientFileName);
  2981. if($fileSize===null || $fileSize < 0)
  2982. $fileSize = ($content===null?filesize($fileName):strlen($content));
  2983. $this->sendHttpHeader();
  2984. if(is_array($headers))
  2985. {
  2986. foreach($headers as $h)
  2987. header($h);
  2988. }
  2989. else
  2990. {
  2991. header('Pragma: public');
  2992. header('Expires: 0');
  2993. header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
  2994. }
  2995. header("Content-type: $mimeType");
  2996. header('Content-Length: '.$fileSize);
  2997. header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
  2998. header('Content-Transfer-Encoding: binary');
  2999. if($content===null)
  3000. readfile($fileName);
  3001. else
  3002. echo $content;
  3003. }
  3004. public function redirect($url)
  3005. {
  3006. if($this->getHasAdapter())
  3007. $this->_adapter->httpRedirect($url);
  3008. else
  3009. $this->httpRedirect($url);
  3010. }
  3011. public function httpRedirect($url)
  3012. {
  3013. if(!$this->getApplication()->getRequestCompleted())
  3014. $this->getApplication()->onEndRequest();
  3015. if($url[0]==='/')
  3016. $url=$this->getRequest()->getBaseUrl().$url;
  3017. if ($this->_status >= 300 && $this->_status < 400)
  3018. header('Location: '.str_replace('&amp;','&',$url), true, $this->_status);
  3019. else
  3020. header('Location: '.str_replace('&amp;','&',$url));
  3021. exit();
  3022. }
  3023. public function reload()
  3024. {
  3025. $this->redirect($this->getRequest()->getRequestUri());
  3026. }
  3027. public function flush()
  3028. {
  3029. if($this->getHasAdapter())
  3030. $this->_adapter->flushContent();
  3031. else
  3032. $this->flushContent();
  3033. }
  3034. public function flushContent()
  3035. {
  3036. $this->sendHttpHeader();
  3037. $this->sendContentTypeHeader();
  3038. if($this->_bufferOutput)
  3039. ob_flush();
  3040. }
  3041. protected function sendHttpHeader ()
  3042. {
  3043. if (($version=$this->getRequest()->getHttpProtocolVersion())==='')
  3044. header (' ', true, $this->_status);
  3045. else
  3046. header($version.' '.$this->_status.' '.$this->_reason, true, $this->_status);
  3047. }
  3048. protected function sendContentTypeHeader()
  3049. {
  3050. $contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
  3051. $charset=$this->getCharset();
  3052. if($charset === false) {
  3053. $this->appendHeader('Content-Type: '.$contentType);
  3054. return;
  3055. }
  3056. if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
  3057. $charset=$globalization->getCharset();
  3058. if($charset==='') $charset = self::DEFAULT_CHARSET;
  3059. $this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
  3060. }
  3061. public function getContents()
  3062. {
  3063. return $this->_bufferOutput?ob_get_contents():'';
  3064. }
  3065. public function clear()
  3066. {
  3067. if($this->_bufferOutput)
  3068. ob_clean();
  3069. }
  3070. public function appendHeader($value)
  3071. {
  3072. header($value);
  3073. }
  3074. public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
  3075. {
  3076. error_log($message,$messageType,$destination,$extraHeaders);
  3077. }
  3078. public function addCookie($cookie)
  3079. {
  3080. $request=$this->getRequest();
  3081. if($request->getEnableCookieValidation())
  3082. {
  3083. $value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
  3084. setcookie(
  3085. $cookie->getName(),
  3086. $value,
  3087. $cookie->getExpire(),
  3088. $cookie->getPath(),
  3089. $cookie->getDomain(),
  3090. $cookie->getSecure()
  3091. );
  3092. }
  3093. else {
  3094. setcookie(
  3095. $cookie->getName(),
  3096. $cookie->getValue(),
  3097. $cookie->getExpire(),
  3098. $cookie->getPath(),
  3099. $cookie->getDomain(),
  3100. $cookie->getSecure()
  3101. );
  3102. }
  3103. }
  3104. public function removeCookie($cookie)
  3105. {
  3106. setcookie(
  3107. $cookie->getName(),
  3108. null,
  3109. 0,
  3110. $cookie->getPath(),
  3111. $cookie->getDomain(),
  3112. $cookie->getSecure()
  3113. );
  3114. }
  3115. public function getHtmlWriterType()
  3116. {
  3117. return $this->_htmlWriterType;
  3118. }
  3119. public function setHtmlWriterType($value)
  3120. {
  3121. $this->_htmlWriterType=$value;
  3122. }
  3123. public function createHtmlWriter($type=null)
  3124. {
  3125. if($type===null)
  3126. $type=$this->getHtmlWriterType();
  3127. if($this->getHasAdapter())
  3128. return $this->_adapter->createNewHtmlWriter($type, $this);
  3129. else
  3130. return $this->createNewHtmlWriter($type, $this);
  3131. }
  3132. public function createNewHtmlWriter($type, $writer)
  3133. {
  3134. return Prado::createComponent($type, $writer);
  3135. }
  3136. }
  3137. class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
  3138. {
  3139. private $_initialized=false;
  3140. private $_started=false;
  3141. private $_autoStart=false;
  3142. private $_cookie=null;
  3143. private $_id;
  3144. private $_customStorage=false;
  3145. public function getID()
  3146. {
  3147. return $this->_id;
  3148. }
  3149. public function setID($value)
  3150. {
  3151. $this->_id=$value;
  3152. }
  3153. public function init($config)
  3154. {
  3155. if($this->_autoStart)
  3156. $this->open();
  3157. $this->_initialized=true;
  3158. $this->getApplication()->setSession($this);
  3159. register_shutdown_function(array($this, "close"));
  3160. }
  3161. public function open()
  3162. {
  3163. if(!$this->_started)
  3164. {
  3165. if($this->_customStorage)
  3166. session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
  3167. if($this->_cookie!==null)
  3168. session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure());
  3169. if(ini_get('session.auto_start')!=='1')
  3170. session_start();
  3171. $this->_started=true;
  3172. }
  3173. }
  3174. public function close()
  3175. {
  3176. if($this->_started)
  3177. {
  3178. session_write_close();
  3179. $this->_started=false;
  3180. }
  3181. }
  3182. public function destroy()
  3183. {
  3184. if($this->_started)
  3185. {
  3186. session_destroy();
  3187. $this->_started=false;
  3188. }
  3189. }
  3190. public function getIsStarted()
  3191. {
  3192. return $this->_started;
  3193. }
  3194. public function getSessionID()
  3195. {
  3196. return session_id();
  3197. }
  3198. public function setSessionID($value)
  3199. {
  3200. if($this->_started)
  3201. throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
  3202. else
  3203. session_id($value);
  3204. }
  3205. public function getSessionName()
  3206. {
  3207. return session_name();
  3208. }
  3209. public function setSessionName($value)
  3210. {
  3211. if($this->_started)
  3212. throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
  3213. else if(ctype_alnum($value))
  3214. session_name($value);
  3215. else
  3216. throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
  3217. }
  3218. public function getSavePath()
  3219. {
  3220. return session_save_path();
  3221. }
  3222. public function setSavePath($value)
  3223. {
  3224. if($this->_started)
  3225. throw new TInvalidOperationException('httpsession_savepath_unchangeable');
  3226. else if(is_dir($value))
  3227. session_save_path($value);
  3228. else
  3229. throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
  3230. }
  3231. public function getUseCustomStorage()
  3232. {
  3233. return $this->_customStorage;
  3234. }
  3235. public function setUseCustomStorage($value)
  3236. {
  3237. $this->_customStorage=TPropertyValue::ensureBoolean($value);
  3238. }
  3239. public function getCookie()
  3240. {
  3241. if($this->_cookie===null)
  3242. $this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
  3243. return $this->_cookie;
  3244. }
  3245. public function getCookieMode()
  3246. {
  3247. if(ini_get('session.use_cookies')==='0')
  3248. return THttpSessionCookieMode::None;
  3249. else if(ini_get('session.use_only_cookies')==='0')
  3250. return THttpSessionCookieMode::Allow;
  3251. else
  3252. return THttpSessionCookieMode::Only;
  3253. }
  3254. public function setCookieMode($value)
  3255. {
  3256. if($this->_started)
  3257. throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
  3258. else
  3259. {
  3260. $value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
  3261. if($value===THttpSessionCookieMode::None)
  3262. ini_set('session.use_cookies','0');
  3263. else if($value===THttpSessionCookieMode::Allow)
  3264. {
  3265. ini_set('session.use_cookies','1');
  3266. ini_set('session.use_only_cookies','0');
  3267. }
  3268. else
  3269. {
  3270. ini_set('session.use_cookies','1');
  3271. ini_set('session.use_only_cookies','1');
  3272. ini_set('session.use_trans_sid', 0);
  3273. }
  3274. }
  3275. }
  3276. public function getAutoStart()
  3277. {
  3278. return $this->_autoStart;
  3279. }
  3280. public function setAutoStart($value)
  3281. {
  3282. if($this->_initialized)
  3283. throw new TInvalidOperationException('httpsession_autostart_unchangeable');
  3284. else
  3285. $this->_autoStart=TPropertyValue::ensureBoolean($value);
  3286. }
  3287. public function getGCProbability()
  3288. {
  3289. return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
  3290. }
  3291. public function setGCProbability($value)
  3292. {
  3293. if($this->_started)
  3294. throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
  3295. else
  3296. {
  3297. $value=TPropertyValue::ensureInteger($value);
  3298. if($value>=0 && $value<=100)
  3299. {
  3300. ini_set('session.gc_probability',$value);
  3301. ini_set('session.gc_divisor','100');
  3302. }
  3303. else
  3304. throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
  3305. }
  3306. }
  3307. public function getUseTransparentSessionID()
  3308. {
  3309. return ini_get('session.use_trans_sid')==='1';
  3310. }
  3311. public function setUseTransparentSessionID($value)
  3312. {
  3313. if($this->_started)
  3314. throw new TInvalidOperationException('httpsession_transid_unchangeable');
  3315. else
  3316. {
  3317. $value=TPropertyValue::ensureBoolean($value);
  3318. if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
  3319. throw new TInvalidOperationException('httpsession_transid_cookieonly');
  3320. ini_set('session.use_trans_sid',$value?'1':'0');
  3321. }
  3322. }
  3323. public function getTimeout()
  3324. {
  3325. return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
  3326. }
  3327. public function setTimeout($value)
  3328. {
  3329. if($this->_started)
  3330. throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
  3331. else
  3332. ini_set('session.gc_maxlifetime',$value);
  3333. }
  3334. public function _open($savePath,$sessionName)
  3335. {
  3336. return true;
  3337. }
  3338. public function _close()
  3339. {
  3340. return true;
  3341. }
  3342. public function _read($id)
  3343. {
  3344. return '';
  3345. }
  3346. public function _write($id,$data)
  3347. {
  3348. return true;
  3349. }
  3350. public function _destroy($id)
  3351. {
  3352. return true;
  3353. }
  3354. public function _gc($maxLifetime)
  3355. {
  3356. return true;
  3357. }
  3358. public function getIterator()
  3359. {
  3360. return new TSessionIterator;
  3361. }
  3362. public function getCount()
  3363. {
  3364. return count($_SESSION);
  3365. }
  3366. public function count()
  3367. {
  3368. return $this->getCount();
  3369. }
  3370. public function getKeys()
  3371. {
  3372. return array_keys($_SESSION);
  3373. }
  3374. public function itemAt($key)
  3375. {
  3376. return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
  3377. }
  3378. public function add($key,$value)
  3379. {
  3380. $_SESSION[$key]=$value;
  3381. }
  3382. public function remove($key)
  3383. {
  3384. if(isset($_SESSION[$key]))
  3385. {
  3386. $value=$_SESSION[$key];
  3387. unset($_SESSION[$key]);
  3388. return $value;
  3389. }
  3390. else
  3391. return null;
  3392. }
  3393. public function clear()
  3394. {
  3395. foreach(array_keys($_SESSION) as $key)
  3396. unset($_SESSION[$key]);
  3397. }
  3398. public function contains($key)
  3399. {
  3400. return isset($_SESSION[$key]);
  3401. }
  3402. public function toArray()
  3403. {
  3404. return $_SESSION;
  3405. }
  3406. public function offsetExists($offset)
  3407. {
  3408. return isset($_SESSION[$offset]);
  3409. }
  3410. public function offsetGet($offset)
  3411. {
  3412. return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
  3413. }
  3414. public function offsetSet($offset,$item)
  3415. {
  3416. $_SESSION[$offset]=$item;
  3417. }
  3418. public function offsetUnset($offset)
  3419. {
  3420. unset($_SESSION[$offset]);
  3421. }
  3422. }
  3423. class TSessionIterator implements Iterator
  3424. {
  3425. private $_keys;
  3426. private $_key;
  3427. public function __construct()
  3428. {
  3429. $this->_keys=array_keys($_SESSION);
  3430. }
  3431. public function rewind()
  3432. {
  3433. $this->_key=reset($this->_keys);
  3434. }
  3435. public function key()
  3436. {
  3437. return $this->_key;
  3438. }
  3439. public function current()
  3440. {
  3441. return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
  3442. }
  3443. public function next()
  3444. {
  3445. do
  3446. {
  3447. $this->_key=next($this->_keys);
  3448. }
  3449. while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
  3450. }
  3451. public function valid()
  3452. {
  3453. return $this->_key!==false;
  3454. }
  3455. }
  3456. class THttpSessionCookieMode extends TEnumerable
  3457. {
  3458. const None='None';
  3459. const Allow='Allow';
  3460. const Only='Only';
  3461. }
  3462. Prado::using('System.Web.UI.WebControls.*');
  3463. class TAttributeCollection extends TMap
  3464. {
  3465. private $_caseSensitive=false;
  3466. public function __get($name)
  3467. {
  3468. return $this->contains($name)?$this->itemAt($name):parent::__get($name);
  3469. }
  3470. public function __set($name,$value)
  3471. {
  3472. $this->add($name,$value);
  3473. }
  3474. public function getCaseSensitive()
  3475. {
  3476. return $this->_caseSensitive;
  3477. }
  3478. public function setCaseSensitive($value)
  3479. {
  3480. $this->_caseSensitive=TPropertyValue::ensureBoolean($value);
  3481. }
  3482. public function itemAt($key)
  3483. {
  3484. return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
  3485. }
  3486. public function add($key,$value)
  3487. {
  3488. parent::add($this->_caseSensitive?$key:strtolower($key),$value);
  3489. }
  3490. public function remove($key)
  3491. {
  3492. return parent::remove($this->_caseSensitive?$key:strtolower($key));
  3493. }
  3494. public function contains($key)
  3495. {
  3496. return parent::contains($this->_caseSensitive?$key:strtolower($key));
  3497. }
  3498. public function hasProperty($name)
  3499. {
  3500. return $this->contains($name) || parent::hasProperty($name);
  3501. }
  3502. public function canGetProperty($name)
  3503. {
  3504. return $this->contains($name) || parent::canGetProperty($name);
  3505. }
  3506. public function canSetProperty($name)
  3507. {
  3508. return true;
  3509. }
  3510. }
  3511. class TControlAdapter extends TApplicationComponent
  3512. {
  3513. private $_control;
  3514. public function __construct($control)
  3515. {
  3516. $this->_control=$control;
  3517. }
  3518. public function getControl()
  3519. {
  3520. return $this->_control;
  3521. }
  3522. public function getPage()
  3523. {
  3524. return $this->_control?$this->_control->getPage():null;
  3525. }
  3526. public function createChildControls()
  3527. {
  3528. $this->_control->createChildControls();
  3529. }
  3530. public function loadState()
  3531. {
  3532. $this->_control->loadState();
  3533. }
  3534. public function saveState()
  3535. {
  3536. $this->_control->saveState();
  3537. }
  3538. public function onInit($param)
  3539. {
  3540. $this->_control->onInit($param);
  3541. }
  3542. public function onLoad($param)
  3543. {
  3544. $this->_control->onLoad($param);
  3545. }
  3546. public function onPreRender($param)
  3547. {
  3548. $this->_control->onPreRender($param);
  3549. }
  3550. public function onUnload($param)
  3551. {
  3552. $this->_control->onUnload($param);
  3553. }
  3554. public function render($writer)
  3555. {
  3556. $this->_control->render($writer);
  3557. }
  3558. public function renderChildren($writer)
  3559. {
  3560. $this->_control->renderChildren($writer);
  3561. }
  3562. }
  3563. class TControl extends TApplicationComponent implements IRenderable, IBindable
  3564. {
  3565. const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
  3566. const ID_SEPARATOR='$';
  3567. const CLIENT_ID_SEPARATOR='_';
  3568. const AUTOMATIC_ID_PREFIX='ctl';
  3569. const CS_CONSTRUCTED=0;
  3570. const CS_CHILD_INITIALIZED=1;
  3571. const CS_INITIALIZED=2;
  3572. const CS_STATE_LOADED=3;
  3573. const CS_LOADED=4;
  3574. const CS_PRERENDERED=5;
  3575. const IS_ID_SET=0x01;
  3576. const IS_DISABLE_VIEWSTATE=0x02;
  3577. const IS_SKIN_APPLIED=0x04;
  3578. const IS_STYLESHEET_APPLIED=0x08;
  3579. const IS_DISABLE_THEMING=0x10;
  3580. const IS_CHILD_CREATED=0x20;
  3581. const IS_CREATING_CHILD=0x40;
  3582. const RF_CONTROLS=0;
  3583. const RF_CHILD_STATE=1;
  3584. const RF_NAMED_CONTROLS=2;
  3585. const RF_NAMED_CONTROLS_ID=3;
  3586. const RF_SKIN_ID=4;
  3587. const RF_DATA_BINDINGS=5;
  3588. const RF_EVENTS=6;
  3589. const RF_CONTROLSTATE=7;
  3590. const RF_NAMED_OBJECTS=8;
  3591. const RF_ADAPTER=9;
  3592. const RF_AUTO_BINDINGS=10;
  3593. private $_id='';
  3594. private $_uid;
  3595. private $_parent;
  3596. private $_page;
  3597. private $_namingContainer;
  3598. private $_tplControl;
  3599. private $_viewState=array();
  3600. private $_tempState=array();
  3601. private $_trackViewState=true;
  3602. private $_stage=0;
  3603. private $_flags=0;
  3604. private $_rf=array();
  3605. public function __construct()
  3606. {
  3607. }
  3608. public function __get($name)
  3609. {
  3610. if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
  3611. return $this->_rf[self::RF_NAMED_OBJECTS][$name];
  3612. else
  3613. return parent::__get($name);
  3614. }
  3615. public function getHasAdapter()
  3616. {
  3617. return isset($this->_rf[self::RF_ADAPTER]);
  3618. }
  3619. public function getAdapter()
  3620. {
  3621. return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
  3622. }
  3623. public function setAdapter(TControlAdapter $adapter)
  3624. {
  3625. $this->_rf[self::RF_ADAPTER]=$adapter;
  3626. }
  3627. public function getParent()
  3628. {
  3629. return $this->_parent;
  3630. }
  3631. public function getNamingContainer()
  3632. {
  3633. if(!$this->_namingContainer && $this->_parent)
  3634. {
  3635. if($this->_parent instanceof INamingContainer)
  3636. $this->_namingContainer=$this->_parent;
  3637. else
  3638. $this->_namingContainer=$this->_parent->getNamingContainer();
  3639. }
  3640. return $this->_namingContainer;
  3641. }
  3642. public function getPage()
  3643. {
  3644. if(!$this->_page)
  3645. {
  3646. if($this->_parent)
  3647. $this->_page=$this->_parent->getPage();
  3648. else if($this->_tplControl)
  3649. $this->_page=$this->_tplControl->getPage();
  3650. }
  3651. return $this->_page;
  3652. }
  3653. public function setPage($page)
  3654. {
  3655. $this->_page=$page;
  3656. }
  3657. public function setTemplateControl($control)
  3658. {
  3659. $this->_tplControl=$control;
  3660. }
  3661. public function getTemplateControl()
  3662. {
  3663. if(!$this->_tplControl && $this->_parent)
  3664. $this->_tplControl=$this->_parent->getTemplateControl();
  3665. return $this->_tplControl;
  3666. }
  3667. public function getSourceTemplateControl()
  3668. {
  3669. $control=$this;
  3670. while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
  3671. {
  3672. if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
  3673. return $control;
  3674. }
  3675. return $this->getPage();
  3676. }
  3677. protected function getControlStage()
  3678. {
  3679. return $this->_stage;
  3680. }
  3681. protected function setControlStage($value)
  3682. {
  3683. $this->_stage=$value;
  3684. }
  3685. public function getID($hideAutoID=true)
  3686. {
  3687. if($hideAutoID)
  3688. return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
  3689. else
  3690. return $this->_id;
  3691. }
  3692. public function setID($id)
  3693. {
  3694. if(!preg_match(self::ID_FORMAT,$id))
  3695. throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
  3696. $this->_id=$id;
  3697. $this->_flags |= self::IS_ID_SET;
  3698. $this->clearCachedUniqueID($this instanceof INamingContainer);
  3699. if($this->_namingContainer)
  3700. $this->_namingContainer->clearNameTable();
  3701. }
  3702. public function getUniqueID()
  3703. {
  3704. if($this->_uid==='' || $this->_uid===null)
  3705. {
  3706. $this->_uid='';
  3707. if($namingContainer=$this->getNamingContainer())
  3708. {
  3709. if($this->getPage()===$namingContainer)
  3710. return ($this->_uid=$this->_id);
  3711. else if(($prefix=$namingContainer->getUniqueID())==='')
  3712. return $this->_id;
  3713. else
  3714. return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
  3715. }
  3716. else
  3717. return $this->_id;
  3718. }
  3719. else
  3720. return $this->_uid;
  3721. }
  3722. public function focus()
  3723. {
  3724. $this->getPage()->setFocus($this);
  3725. }
  3726. public function getClientID()
  3727. {
  3728. return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
  3729. }
  3730. public static function convertUniqueIdToClientId($uniqueID)
  3731. {
  3732. return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
  3733. }
  3734. public function getSkinID()
  3735. {
  3736. return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
  3737. }
  3738. public function setSkinID($value)
  3739. {
  3740. if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
  3741. throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
  3742. else
  3743. $this->_rf[self::RF_SKIN_ID]=$value;
  3744. }
  3745. public function getEnableTheming()
  3746. {
  3747. if($this->_flags & self::IS_DISABLE_THEMING)
  3748. return false;
  3749. else
  3750. return $this->_parent?$this->_parent->getEnableTheming():true;
  3751. }
  3752. public function setEnableTheming($value)
  3753. {
  3754. if($this->_stage>=self::CS_CHILD_INITIALIZED)
  3755. throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
  3756. else if(TPropertyValue::ensureBoolean($value))
  3757. $this->_flags &= ~self::IS_DISABLE_THEMING;
  3758. else
  3759. $this->_flags |= self::IS_DISABLE_THEMING;
  3760. }
  3761. public function getCustomData()
  3762. {
  3763. return $this->getViewState('CustomData',null);
  3764. }
  3765. public function setCustomData($value)
  3766. {
  3767. $this->setViewState('CustomData',$value,null);
  3768. }
  3769. public function getHasControls()
  3770. {
  3771. return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
  3772. }
  3773. public function getControls()
  3774. {
  3775. if(!isset($this->_rf[self::RF_CONTROLS]))
  3776. $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
  3777. return $this->_rf[self::RF_CONTROLS];
  3778. }
  3779. protected function createControlCollection()
  3780. {
  3781. return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
  3782. }
  3783. public function getVisible($checkParents=true)
  3784. {
  3785. if($checkParents)
  3786. {
  3787. for($control=$this;$control;$control=$control->_parent)
  3788. if(!$control->getVisible(false))
  3789. return false;
  3790. return true;
  3791. }
  3792. else
  3793. return $this->getViewState('Visible',true);
  3794. }
  3795. public function setVisible($value)
  3796. {
  3797. $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
  3798. }
  3799. public function getEnabled($checkParents=false)
  3800. {
  3801. if($checkParents)
  3802. {
  3803. for($control=$this;$control;$control=$control->_parent)
  3804. if(!$control->getViewState('Enabled',true))
  3805. return false;
  3806. return true;
  3807. }
  3808. else
  3809. return $this->getViewState('Enabled',true);
  3810. }
  3811. public function setEnabled($value)
  3812. {
  3813. $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
  3814. }
  3815. public function getHasAttributes()
  3816. {
  3817. if($attributes=$this->getViewState('Attributes',null))
  3818. return $attributes->getCount()>0;
  3819. else
  3820. return false;
  3821. }
  3822. public function getAttributes()
  3823. {
  3824. if($attributes=$this->getViewState('Attributes',null))
  3825. return $attributes;
  3826. else
  3827. {
  3828. $attributes=new TAttributeCollection;
  3829. $this->setViewState('Attributes',$attributes,null);
  3830. return $attributes;
  3831. }
  3832. }
  3833. public function hasAttribute($name)
  3834. {
  3835. if($attributes=$this->getViewState('Attributes',null))
  3836. return $attributes->contains($name);
  3837. else
  3838. return false;
  3839. }
  3840. public function getAttribute($name)
  3841. {
  3842. if($attributes=$this->getViewState('Attributes',null))
  3843. return $attributes->itemAt($name);
  3844. else
  3845. return null;
  3846. }
  3847. public function setAttribute($name,$value)
  3848. {
  3849. $this->getAttributes()->add($name,$value);
  3850. }
  3851. public function removeAttribute($name)
  3852. {
  3853. if($attributes=$this->getViewState('Attributes',null))
  3854. return $attributes->remove($name);
  3855. else
  3856. return null;
  3857. }
  3858. public function getEnableViewState($checkParents=false)
  3859. {
  3860. if($checkParents)
  3861. {
  3862. for($control=$this;$control!==null;$control=$control->getParent())
  3863. if($control->_flags & self::IS_DISABLE_VIEWSTATE)
  3864. return false;
  3865. return true;
  3866. }
  3867. else
  3868. return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
  3869. }
  3870. public function setEnableViewState($value)
  3871. {
  3872. if(TPropertyValue::ensureBoolean($value))
  3873. $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
  3874. else
  3875. $this->_flags |= self::IS_DISABLE_VIEWSTATE;
  3876. }
  3877. protected function getControlState($key,$defaultValue=null)
  3878. {
  3879. return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
  3880. }
  3881. protected function setControlState($key,$value,$defaultValue=null)
  3882. {
  3883. if($value===$defaultValue)
  3884. unset($this->_rf[self::RF_CONTROLSTATE][$key]);
  3885. else
  3886. $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
  3887. }
  3888. protected function clearControlState($key)
  3889. {
  3890. unset($this->_rf[self::RF_CONTROLSTATE][$key]);
  3891. }
  3892. public function trackViewState($enabled)
  3893. {
  3894. $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
  3895. }
  3896. public function getViewState($key,$defaultValue=null)
  3897. {
  3898. if(isset($this->_viewState[$key]))
  3899. return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
  3900. else if(isset($this->_tempState[$key]))
  3901. {
  3902. if(is_object($this->_tempState[$key]) && $this->_trackViewState)
  3903. $this->_viewState[$key]=$this->_tempState[$key];
  3904. return $this->_tempState[$key];
  3905. }
  3906. else
  3907. return $defaultValue;
  3908. }
  3909. public function setViewState($key,$value,$defaultValue=null)
  3910. {
  3911. if($this->_trackViewState)
  3912. {
  3913. $this->_viewState[$key]=$value;
  3914. unset($this->_tempState[$key]);
  3915. }
  3916. else
  3917. {
  3918. unset($this->_viewState[$key]);
  3919. $this->_tempState[$key]=$value;
  3920. }
  3921. }
  3922. public function clearViewState($key)
  3923. {
  3924. unset($this->_viewState[$key]);
  3925. unset($this->_tempState[$key]);
  3926. }
  3927. public function bindProperty($name,$expression)
  3928. {
  3929. $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
  3930. }
  3931. public function unbindProperty($name)
  3932. {
  3933. unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
  3934. }
  3935. public function autoBindProperty($name,$expression)
  3936. {
  3937. $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
  3938. }
  3939. public function dataBind()
  3940. {
  3941. $this->dataBindProperties();
  3942. $this->onDataBinding(null);
  3943. $this->dataBindChildren();
  3944. }
  3945. protected function dataBindProperties()
  3946. {
  3947. if(isset($this->_rf[self::RF_DATA_BINDINGS]))
  3948. {
  3949. if(($context=$this->getTemplateControl())===null)
  3950. $context=$this;
  3951. foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
  3952. $this->setSubProperty($property,$context->evaluateExpression($expression));
  3953. }
  3954. }
  3955. protected function autoDataBindProperties()
  3956. {
  3957. if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
  3958. {
  3959. if(($context=$this->getTemplateControl())===null)
  3960. $context=$this;
  3961. foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
  3962. $this->setSubProperty($property,$context->evaluateExpression($expression));
  3963. }
  3964. }
  3965. protected function dataBindChildren()
  3966. {
  3967. if(isset($this->_rf[self::RF_CONTROLS]))
  3968. {
  3969. foreach($this->_rf[self::RF_CONTROLS] as $control)
  3970. if($control instanceof IBindable)
  3971. $control->dataBind();
  3972. }
  3973. }
  3974. final protected function getChildControlsCreated()
  3975. {
  3976. return ($this->_flags & self::IS_CHILD_CREATED)!==0;
  3977. }
  3978. final protected function setChildControlsCreated($value)
  3979. {
  3980. if($value)
  3981. $this->_flags |= self::IS_CHILD_CREATED;
  3982. else
  3983. {
  3984. if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
  3985. $this->getControls()->clear();
  3986. $this->_flags &= ~self::IS_CHILD_CREATED;
  3987. }
  3988. }
  3989. public function ensureChildControls()
  3990. {
  3991. if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
  3992. {
  3993. try
  3994. {
  3995. $this->_flags |= self::IS_CREATING_CHILD;
  3996. if(isset($this->_rf[self::RF_ADAPTER]))
  3997. $this->_rf[self::RF_ADAPTER]->createChildControls();
  3998. else
  3999. $this->createChildControls();
  4000. $this->_flags &= ~self::IS_CREATING_CHILD;
  4001. $this->_flags |= self::IS_CHILD_CREATED;
  4002. }
  4003. catch(Exception $e)
  4004. {
  4005. $this->_flags &= ~self::IS_CREATING_CHILD;
  4006. $this->_flags |= self::IS_CHILD_CREATED;
  4007. throw $e;
  4008. }
  4009. }
  4010. }
  4011. public function createChildControls()
  4012. {
  4013. }
  4014. public function findControl($id)
  4015. {
  4016. $id=strtr($id,'.',self::ID_SEPARATOR);
  4017. $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
  4018. if(!$container || !$container->getHasControls())
  4019. return null;
  4020. if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
  4021. {
  4022. $container->_rf[self::RF_NAMED_CONTROLS]=array();
  4023. $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
  4024. }
  4025. if(($pos=strpos($id,self::ID_SEPARATOR))===false)
  4026. return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
  4027. else
  4028. {
  4029. $cid=substr($id,0,$pos);
  4030. $sid=substr($id,$pos+1);
  4031. if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
  4032. return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
  4033. else
  4034. return null;
  4035. }
  4036. }
  4037. public function findControlsByType($type,$strict=true)
  4038. {
  4039. $controls=array();
  4040. if($this->getHasControls())
  4041. {
  4042. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4043. {
  4044. if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
  4045. $controls[]=$control;
  4046. if(($control instanceof TControl) && $control->getHasControls())
  4047. $controls=array_merge($controls,$control->findControlsByType($type,$strict));
  4048. }
  4049. }
  4050. return $controls;
  4051. }
  4052. public function findControlsByID($id)
  4053. {
  4054. $controls=array();
  4055. if($this->getHasControls())
  4056. {
  4057. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4058. {
  4059. if($control instanceof TControl)
  4060. {
  4061. if($control->_id===$id)
  4062. $controls[]=$control;
  4063. $controls=array_merge($controls,$control->findControlsByID($id));
  4064. }
  4065. }
  4066. }
  4067. return $controls;
  4068. }
  4069. public function clearNamingContainer()
  4070. {
  4071. unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
  4072. $this->clearNameTable();
  4073. }
  4074. public function registerObject($name,$object)
  4075. {
  4076. if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
  4077. throw new TInvalidOperationException('control_object_reregistered',$name);
  4078. $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
  4079. }
  4080. public function unregisterObject($name)
  4081. {
  4082. unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
  4083. }
  4084. public function isObjectRegistered($name)
  4085. {
  4086. return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
  4087. }
  4088. public function getHasChildInitialized()
  4089. {
  4090. return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
  4091. }
  4092. public function getHasInitialized()
  4093. {
  4094. return $this->getControlStage() >= self::CS_INITIALIZED;
  4095. }
  4096. public function getHasLoadedPostData()
  4097. {
  4098. return $this->getControlStage() >= self::CS_STATE_LOADED;
  4099. }
  4100. public function getHasLoaded()
  4101. {
  4102. return $this->getControlStage() >= self::CS_LOADED;
  4103. }
  4104. public function getHasPreRendered()
  4105. {
  4106. return $this->getControlStage() >= self::CS_PRERENDERED;
  4107. }
  4108. public function getRegisteredObject($name)
  4109. {
  4110. return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
  4111. }
  4112. public function getAllowChildControls()
  4113. {
  4114. return true;
  4115. }
  4116. public function addParsedObject($object)
  4117. {
  4118. $this->getControls()->add($object);
  4119. }
  4120. final protected function clearChildState()
  4121. {
  4122. unset($this->_rf[self::RF_CHILD_STATE]);
  4123. }
  4124. final protected function isDescendentOf($ancestor)
  4125. {
  4126. $control=$this;
  4127. while($control!==$ancestor && $control->_parent)
  4128. $control=$control->_parent;
  4129. return $control===$ancestor;
  4130. }
  4131. public function addedControl($control)
  4132. {
  4133. if($control->_parent)
  4134. $control->_parent->getControls()->remove($control);
  4135. $control->_parent=$this;
  4136. $control->_page=$this->getPage();
  4137. $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
  4138. if($namingContainer)
  4139. {
  4140. $control->_namingContainer=$namingContainer;
  4141. if($control->_id==='')
  4142. $control->generateAutomaticID();
  4143. else
  4144. $namingContainer->clearNameTable();
  4145. $control->clearCachedUniqueID($control instanceof INamingContainer);
  4146. }
  4147. if($this->_stage>=self::CS_CHILD_INITIALIZED)
  4148. {
  4149. $control->initRecursive($namingContainer);
  4150. if($this->_stage>=self::CS_STATE_LOADED)
  4151. {
  4152. if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
  4153. {
  4154. $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
  4155. unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
  4156. }
  4157. else
  4158. $state=null;
  4159. $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
  4160. if($this->_stage>=self::CS_LOADED)
  4161. {
  4162. $control->loadRecursive();
  4163. if($this->_stage>=self::CS_PRERENDERED)
  4164. $control->preRenderRecursive();
  4165. }
  4166. }
  4167. }
  4168. }
  4169. public function removedControl($control)
  4170. {
  4171. if($this->_namingContainer)
  4172. $this->_namingContainer->clearNameTable();
  4173. $control->unloadRecursive();
  4174. $control->_parent=null;
  4175. $control->_page=null;
  4176. $control->_namingContainer=null;
  4177. $control->_tplControl=null;
  4178. if(!($control->_flags & self::IS_ID_SET))
  4179. $control->_id='';
  4180. else
  4181. unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
  4182. $control->clearCachedUniqueID(true);
  4183. }
  4184. protected function initRecursive($namingContainer=null)
  4185. {
  4186. $this->ensureChildControls();
  4187. if($this->getHasControls())
  4188. {
  4189. if($this instanceof INamingContainer)
  4190. $namingContainer=$this;
  4191. $page=$this->getPage();
  4192. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4193. {
  4194. if($control instanceof TControl)
  4195. {
  4196. $control->_namingContainer=$namingContainer;
  4197. $control->_page=$page;
  4198. if($control->_id==='' && $namingContainer)
  4199. $control->generateAutomaticID();
  4200. $control->initRecursive($namingContainer);
  4201. }
  4202. }
  4203. }
  4204. if($this->_stage<self::CS_INITIALIZED)
  4205. {
  4206. $this->_stage=self::CS_CHILD_INITIALIZED;
  4207. if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
  4208. {
  4209. $page->applyControlSkin($this);
  4210. $this->_flags |= self::IS_SKIN_APPLIED;
  4211. }
  4212. if(isset($this->_rf[self::RF_ADAPTER]))
  4213. $this->_rf[self::RF_ADAPTER]->onInit(null);
  4214. else
  4215. $this->onInit(null);
  4216. $this->_stage=self::CS_INITIALIZED;
  4217. }
  4218. }
  4219. protected function loadRecursive()
  4220. {
  4221. if($this->_stage<self::CS_LOADED)
  4222. {
  4223. if(isset($this->_rf[self::RF_ADAPTER]))
  4224. $this->_rf[self::RF_ADAPTER]->onLoad(null);
  4225. else
  4226. $this->onLoad(null);
  4227. }
  4228. if($this->getHasControls())
  4229. {
  4230. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4231. {
  4232. if($control instanceof TControl)
  4233. $control->loadRecursive();
  4234. }
  4235. }
  4236. if($this->_stage<self::CS_LOADED)
  4237. $this->_stage=self::CS_LOADED;
  4238. }
  4239. protected function preRenderRecursive()
  4240. {
  4241. $this->autoDataBindProperties();
  4242. if($this->getVisible(false))
  4243. {
  4244. if(isset($this->_rf[self::RF_ADAPTER]))
  4245. $this->_rf[self::RF_ADAPTER]->onPreRender(null);
  4246. else
  4247. $this->onPreRender(null);
  4248. if($this->getHasControls())
  4249. {
  4250. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4251. {
  4252. if($control instanceof TControl)
  4253. $control->preRenderRecursive();
  4254. else if($control instanceof TCompositeLiteral)
  4255. $control->evaluateDynamicContent();
  4256. }
  4257. }
  4258. $this->addToPostDataLoader();
  4259. }
  4260. $this->_stage=self::CS_PRERENDERED;
  4261. }
  4262. protected function addToPostDataLoader()
  4263. {
  4264. if($this instanceof IPostBackDataHandler)
  4265. $this->getPage()->registerPostDataLoader($this);
  4266. }
  4267. protected function unloadRecursive()
  4268. {
  4269. if(!($this->_flags & self::IS_ID_SET))
  4270. $this->_id='';
  4271. if($this->getHasControls())
  4272. {
  4273. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4274. if($control instanceof TControl)
  4275. $control->unloadRecursive();
  4276. }
  4277. if(isset($this->_rf[self::RF_ADAPTER]))
  4278. $this->_rf[self::RF_ADAPTER]->onUnload(null);
  4279. else
  4280. $this->onUnload(null);
  4281. }
  4282. public function onInit($param)
  4283. {
  4284. $this->raiseEvent('OnInit',$this,$param);
  4285. }
  4286. public function onLoad($param)
  4287. {
  4288. $this->raiseEvent('OnLoad',$this,$param);
  4289. }
  4290. public function onDataBinding($param)
  4291. {
  4292. $this->raiseEvent('OnDataBinding',$this,$param);
  4293. }
  4294. public function onUnload($param)
  4295. {
  4296. $this->raiseEvent('OnUnload',$this,$param);
  4297. }
  4298. public function onPreRender($param)
  4299. {
  4300. $this->raiseEvent('OnPreRender',$this,$param);
  4301. }
  4302. protected function raiseBubbleEvent($sender,$param)
  4303. {
  4304. $control=$this;
  4305. while($control=$control->_parent)
  4306. {
  4307. if($control->bubbleEvent($sender,$param))
  4308. break;
  4309. }
  4310. }
  4311. public function bubbleEvent($sender,$param)
  4312. {
  4313. return false;
  4314. }
  4315. public function broadcastEvent($name,$sender,$param)
  4316. {
  4317. $rootControl=(($page=$this->getPage())===null)?$this:$page;
  4318. $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
  4319. }
  4320. private function broadcastEventInternal($name,$sender,$param)
  4321. {
  4322. if($this->hasEvent($name))
  4323. $this->raiseEvent($name,$sender,$param->getParameter());
  4324. if($this instanceof IBroadcastEventReceiver)
  4325. $this->broadcastEventReceived($sender,$param);
  4326. if($this->getHasControls())
  4327. {
  4328. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4329. {
  4330. if($control instanceof TControl)
  4331. $control->broadcastEventInternal($name,$sender,$param);
  4332. }
  4333. }
  4334. }
  4335. protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
  4336. {
  4337. if($preCallback!==null)
  4338. call_user_func($preCallback,$this,$param);
  4339. if($this->getHasControls())
  4340. {
  4341. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4342. {
  4343. if($control instanceof TControl)
  4344. {
  4345. $control->traverseChildControls($param,$preCallback,$postCallback);
  4346. }
  4347. }
  4348. }
  4349. if($postCallback!==null)
  4350. call_user_func($postCallback,$this,$param);
  4351. }
  4352. public function renderControl($writer)
  4353. {
  4354. if($this->getVisible(false))
  4355. {
  4356. if(isset($this->_rf[self::RF_ADAPTER]))
  4357. $this->_rf[self::RF_ADAPTER]->render($writer);
  4358. else
  4359. $this->render($writer);
  4360. }
  4361. }
  4362. public function render($writer)
  4363. {
  4364. $this->renderChildren($writer);
  4365. }
  4366. public function renderChildren($writer)
  4367. {
  4368. if($this->getHasControls())
  4369. {
  4370. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4371. {
  4372. if(is_string($control))
  4373. $writer->write($control);
  4374. else if($control instanceof TControl)
  4375. $control->renderControl($writer);
  4376. else if($control instanceof IRenderable)
  4377. $control->render($writer);
  4378. }
  4379. }
  4380. }
  4381. public function saveState()
  4382. {
  4383. }
  4384. public function loadState()
  4385. {
  4386. }
  4387. protected function loadStateRecursive(&$state,$needViewState=true)
  4388. {
  4389. if(is_array($state))
  4390. {
  4391. $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
  4392. if(isset($state[1]))
  4393. {
  4394. $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
  4395. unset($state[1]);
  4396. }
  4397. else
  4398. unset($this->_rf[self::RF_CONTROLSTATE]);
  4399. if($needViewState)
  4400. {
  4401. if(isset($state[0]))
  4402. $this->_viewState=&$state[0];
  4403. else
  4404. $this->_viewState=array();
  4405. }
  4406. unset($state[0]);
  4407. if($this->getHasControls())
  4408. {
  4409. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4410. {
  4411. if($control instanceof TControl)
  4412. {
  4413. if(isset($state[$control->_id]))
  4414. {
  4415. $control->loadStateRecursive($state[$control->_id],$needViewState);
  4416. unset($state[$control->_id]);
  4417. }
  4418. }
  4419. }
  4420. }
  4421. if(!empty($state))
  4422. $this->_rf[self::RF_CHILD_STATE]=&$state;
  4423. }
  4424. $this->_stage=self::CS_STATE_LOADED;
  4425. if(isset($this->_rf[self::RF_ADAPTER]))
  4426. $this->_rf[self::RF_ADAPTER]->loadState();
  4427. else
  4428. $this->loadState();
  4429. }
  4430. protected function &saveStateRecursive($needViewState=true)
  4431. {
  4432. if(isset($this->_rf[self::RF_ADAPTER]))
  4433. $this->_rf[self::RF_ADAPTER]->saveState();
  4434. else
  4435. $this->saveState();
  4436. $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
  4437. $state=array();
  4438. if($this->getHasControls())
  4439. {
  4440. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4441. {
  4442. if($control instanceof TControl)
  4443. $state[$control->_id]=&$control->saveStateRecursive($needViewState);
  4444. }
  4445. }
  4446. if($needViewState && !empty($this->_viewState))
  4447. $state[0]=&$this->_viewState;
  4448. if(isset($this->_rf[self::RF_CONTROLSTATE]))
  4449. $state[1]=&$this->_rf[self::RF_CONTROLSTATE];
  4450. return $state;
  4451. }
  4452. public function applyStyleSheetSkin($page)
  4453. {
  4454. if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
  4455. {
  4456. $page->applyControlStyleSheet($this);
  4457. $this->_flags |= self::IS_STYLESHEET_APPLIED;
  4458. }
  4459. else if($this->_flags & self::IS_STYLESHEET_APPLIED)
  4460. throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
  4461. }
  4462. private function clearCachedUniqueID($recursive)
  4463. {
  4464. if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
  4465. {
  4466. foreach($this->_rf[self::RF_CONTROLS] as $control)
  4467. if($control instanceof TControl)
  4468. $control->clearCachedUniqueID($recursive);
  4469. }
  4470. $this->_uid=null;
  4471. }
  4472. private function generateAutomaticID()
  4473. {
  4474. $this->_flags &= ~self::IS_ID_SET;
  4475. if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
  4476. $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
  4477. $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
  4478. $this->_id=self::AUTOMATIC_ID_PREFIX . $id;
  4479. $this->_namingContainer->clearNameTable();
  4480. }
  4481. private function clearNameTable()
  4482. {
  4483. unset($this->_rf[self::RF_NAMED_CONTROLS]);
  4484. }
  4485. private function fillNameTable($container,$controls)
  4486. {
  4487. foreach($controls as $control)
  4488. {
  4489. if($control instanceof TControl)
  4490. {
  4491. if($control->_id!=='')
  4492. {
  4493. if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
  4494. throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
  4495. else
  4496. $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
  4497. }
  4498. if(!($control instanceof INamingContainer) && $control->getHasControls())
  4499. $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
  4500. }
  4501. }
  4502. }
  4503. }
  4504. class TControlCollection extends TList
  4505. {
  4506. private $_o;
  4507. public function __construct(TControl $owner,$readOnly=false)
  4508. {
  4509. $this->_o=$owner;
  4510. parent::__construct(null,$readOnly);
  4511. }
  4512. protected function getOwner()
  4513. {
  4514. return $this->_o;
  4515. }
  4516. public function insertAt($index,$item)
  4517. {
  4518. if($item instanceof TControl)
  4519. {
  4520. parent::insertAt($index,$item);
  4521. $this->_o->addedControl($item);
  4522. }
  4523. else if(is_string($item) || ($item instanceof IRenderable))
  4524. parent::insertAt($index,$item);
  4525. else
  4526. throw new TInvalidDataTypeException('controlcollection_control_required');
  4527. }
  4528. public function removeAt($index)
  4529. {
  4530. $item=parent::removeAt($index);
  4531. if($item instanceof TControl)
  4532. $this->_o->removedControl($item);
  4533. return $item;
  4534. }
  4535. public function clear()
  4536. {
  4537. parent::clear();
  4538. if($this->_o instanceof INamingContainer)
  4539. $this->_o->clearNamingContainer();
  4540. }
  4541. }
  4542. class TEmptyControlCollection extends TControlCollection
  4543. {
  4544. public function __construct(TControl $owner)
  4545. {
  4546. parent::__construct($owner,true);
  4547. }
  4548. public function insertAt($index,$item)
  4549. {
  4550. if(!is_string($item))
  4551. parent::insertAt($index,$item);
  4552. }
  4553. }
  4554. interface INamingContainer
  4555. {
  4556. }
  4557. interface IPostBackEventHandler
  4558. {
  4559. public function raisePostBackEvent($param);
  4560. }
  4561. interface IPostBackDataHandler
  4562. {
  4563. public function loadPostData($key,$values);
  4564. public function raisePostDataChangedEvent();
  4565. public function getDataChanged();
  4566. }
  4567. interface IValidator
  4568. {
  4569. public function validate();
  4570. public function getIsValid();
  4571. public function setIsValid($value);
  4572. public function getErrorMessage();
  4573. public function setErrorMessage($value);
  4574. }
  4575. interface IValidatable
  4576. {
  4577. public function getValidationPropertyValue();
  4578. public function getIsValid();
  4579. public function setIsValid($value);
  4580. }
  4581. interface IBroadcastEventReceiver
  4582. {
  4583. public function broadcastEventReceived($sender,$param);
  4584. }
  4585. interface ITheme
  4586. {
  4587. public function applySkin($control);
  4588. }
  4589. interface ITemplate
  4590. {
  4591. public function instantiateIn($parent);
  4592. }
  4593. interface IButtonControl
  4594. {
  4595. public function getText();
  4596. public function setText($value);
  4597. public function getCausesValidation();
  4598. public function setCausesValidation($value);
  4599. public function getCommandName();
  4600. public function setCommandName($value);
  4601. public function getCommandParameter();
  4602. public function setCommandParameter($value);
  4603. public function getValidationGroup();
  4604. public function setValidationGroup($value);
  4605. public function onClick($param);
  4606. public function onCommand($param);
  4607. public function setIsDefaultButton($value);
  4608. public function getIsDefaultButton();
  4609. }
  4610. interface ISurroundable
  4611. {
  4612. public function getSurroundingTagID();
  4613. }
  4614. class TBroadcastEventParameter extends TEventParameter
  4615. {
  4616. private $_name;
  4617. private $_param;
  4618. public function __construct($name='',$parameter=null)
  4619. {
  4620. $this->_name=$name;
  4621. $this->_param=$parameter;
  4622. }
  4623. public function getName()
  4624. {
  4625. return $this->_name;
  4626. }
  4627. public function setName($value)
  4628. {
  4629. $this->_name=$value;
  4630. }
  4631. public function getParameter()
  4632. {
  4633. return $this->_param;
  4634. }
  4635. public function setParameter($value)
  4636. {
  4637. $this->_param=$value;
  4638. }
  4639. }
  4640. class TCommandEventParameter extends TEventParameter
  4641. {
  4642. private $_name;
  4643. private $_param;
  4644. public function __construct($name='',$parameter='')
  4645. {
  4646. $this->_name=$name;
  4647. $this->_param=$parameter;
  4648. }
  4649. public function getCommandName()
  4650. {
  4651. return $this->_name;
  4652. }
  4653. public function getCommandParameter()
  4654. {
  4655. return $this->_param;
  4656. }
  4657. }
  4658. class TCompositeLiteral extends TComponent implements IRenderable, IBindable
  4659. {
  4660. const TYPE_EXPRESSION=0;
  4661. const TYPE_STATEMENTS=1;
  4662. const TYPE_DATABINDING=2;
  4663. private $_container=null;
  4664. private $_items=array();
  4665. private $_expressions=array();
  4666. private $_statements=array();
  4667. private $_bindings=array();
  4668. public function __construct($items)
  4669. {
  4670. $this->_items=array();
  4671. $this->_expressions=array();
  4672. $this->_statements=array();
  4673. foreach($items as $id=>$item)
  4674. {
  4675. if(is_array($item))
  4676. {
  4677. if($item[0]===self::TYPE_EXPRESSION)
  4678. $this->_expressions[$id]=$item[1];
  4679. else if($item[0]===self::TYPE_STATEMENTS)
  4680. $this->_statements[$id]=$item[1];
  4681. else if($item[0]===self::TYPE_DATABINDING)
  4682. $this->_bindings[$id]=$item[1];
  4683. $this->_items[$id]='';
  4684. }
  4685. else
  4686. $this->_items[$id]=$item;
  4687. }
  4688. }
  4689. public function getContainer()
  4690. {
  4691. return $this->_container;
  4692. }
  4693. public function setContainer(TComponent $value)
  4694. {
  4695. $this->_container=$value;
  4696. }
  4697. public function evaluateDynamicContent()
  4698. {
  4699. $context=$this->_container===null?$this:$this->_container;
  4700. foreach($this->_expressions as $id=>$expression)
  4701. $this->_items[$id]=$context->evaluateExpression($expression);
  4702. foreach($this->_statements as $id=>$statement)
  4703. $this->_items[$id]=$context->evaluateStatements($statement);
  4704. }
  4705. public function dataBind()
  4706. {
  4707. $context=$this->_container===null?$this:$this->_container;
  4708. foreach($this->_bindings as $id=>$binding)
  4709. $this->_items[$id]=$context->evaluateExpression($binding);
  4710. }
  4711. public function render($writer)
  4712. {
  4713. $writer->write(implode('',$this->_items));
  4714. }
  4715. }
  4716. class TFont extends TComponent
  4717. {
  4718. const IS_BOLD=0x01;
  4719. const IS_ITALIC=0x02;
  4720. const IS_OVERLINE=0x04;
  4721. const IS_STRIKEOUT=0x08;
  4722. const IS_UNDERLINE=0x10;
  4723. const IS_SET_BOLD=0x01000;
  4724. const IS_SET_ITALIC=0x02000;
  4725. const IS_SET_OVERLINE=0x04000;
  4726. const IS_SET_STRIKEOUT=0x08000;
  4727. const IS_SET_UNDERLINE=0x10000;
  4728. const IS_SET_SIZE=0x20000;
  4729. const IS_SET_NAME=0x40000;
  4730. private $_flags=0;
  4731. private $_name='';
  4732. private $_size='';
  4733. public function getBold()
  4734. {
  4735. return ($this->_flags & self::IS_BOLD)!==0;
  4736. }
  4737. public function setBold($value)
  4738. {
  4739. $this->_flags |= self::IS_SET_BOLD;
  4740. if(TPropertyValue::ensureBoolean($value))
  4741. $this->_flags |= self::IS_BOLD;
  4742. else
  4743. $this->_flags &= ~self::IS_BOLD;
  4744. }
  4745. public function getItalic()
  4746. {
  4747. return ($this->_flags & self::IS_ITALIC)!==0;
  4748. }
  4749. public function setItalic($value)
  4750. {
  4751. $this->_flags |= self::IS_SET_ITALIC;
  4752. if(TPropertyValue::ensureBoolean($value))
  4753. $this->_flags |= self::IS_ITALIC;
  4754. else
  4755. $this->_flags &= ~self::IS_ITALIC;
  4756. }
  4757. public function getOverline()
  4758. {
  4759. return ($this->_flags & self::IS_OVERLINE)!==0;
  4760. }
  4761. public function setOverline($value)
  4762. {
  4763. $this->_flags |= self::IS_SET_OVERLINE;
  4764. if(TPropertyValue::ensureBoolean($value))
  4765. $this->_flags |= self::IS_OVERLINE;
  4766. else
  4767. $this->_flags &= ~self::IS_OVERLINE;
  4768. }
  4769. public function getSize()
  4770. {
  4771. return $this->_size;
  4772. }
  4773. public function setSize($value)
  4774. {
  4775. $this->_flags |= self::IS_SET_SIZE;
  4776. $this->_size=$value;
  4777. }
  4778. public function getStrikeout()
  4779. {
  4780. return ($this->_flags & self::IS_STRIKEOUT)!==0;
  4781. }
  4782. public function setStrikeout($value)
  4783. {
  4784. $this->_flags |= self::IS_SET_STRIKEOUT;
  4785. if(TPropertyValue::ensureBoolean($value))
  4786. $this->_flags |= self::IS_STRIKEOUT;
  4787. else
  4788. $this->_flags &= ~self::IS_STRIKEOUT;
  4789. }
  4790. public function getUnderline()
  4791. {
  4792. return ($this->_flags & self::IS_UNDERLINE)!==0;
  4793. }
  4794. public function setUnderline($value)
  4795. {
  4796. $this->_flags |= self::IS_SET_UNDERLINE;
  4797. if(TPropertyValue::ensureBoolean($value))
  4798. $this->_flags |= self::IS_UNDERLINE;
  4799. else
  4800. $this->_flags &= ~self::IS_UNDERLINE;
  4801. }
  4802. public function getName()
  4803. {
  4804. return $this->_name;
  4805. }
  4806. public function setName($value)
  4807. {
  4808. $this->_flags |= self::IS_SET_NAME;
  4809. $this->_name=$value;
  4810. }
  4811. public function getIsEmpty()
  4812. {
  4813. return !$this->_flags;
  4814. }
  4815. public function reset()
  4816. {
  4817. $this->_flags=0;
  4818. $this->_name='';
  4819. $this->_size='';
  4820. }
  4821. public function mergeWith($font)
  4822. {
  4823. if($font===null || $font->_flags===0)
  4824. return;
  4825. if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
  4826. $this->setBold($font->getBold());
  4827. if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
  4828. $this->setItalic($font->getItalic());
  4829. if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
  4830. $this->setOverline($font->getOverline());
  4831. if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
  4832. $this->setStrikeout($font->getStrikeout());
  4833. if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
  4834. $this->setUnderline($font->getUnderline());
  4835. if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
  4836. $this->setSize($font->getSize());
  4837. if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
  4838. $this->setName($font->getName());
  4839. }
  4840. public function copyFrom($font)
  4841. {
  4842. if($font===null || $font->_flags===0)
  4843. return;
  4844. if($font->_flags & self::IS_SET_BOLD)
  4845. $this->setBold($font->getBold());
  4846. if($font->_flags & self::IS_SET_ITALIC)
  4847. $this->setItalic($font->getItalic());
  4848. if($font->_flags & self::IS_SET_OVERLINE)
  4849. $this->setOverline($font->getOverline());
  4850. if($font->_flags & self::IS_SET_STRIKEOUT)
  4851. $this->setStrikeout($font->getStrikeout());
  4852. if($font->_flags & self::IS_SET_UNDERLINE)
  4853. $this->setUnderline($font->getUnderline());
  4854. if($font->_flags & self::IS_SET_SIZE)
  4855. $this->setSize($font->getSize());
  4856. if($font->_flags & self::IS_SET_NAME)
  4857. $this->setName($font->getName());
  4858. }
  4859. public function toString()
  4860. {
  4861. if($this->_flags===0)
  4862. return '';
  4863. $str='';
  4864. if($this->_flags & self::IS_SET_BOLD)
  4865. $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
  4866. if($this->_flags & self::IS_SET_ITALIC)
  4867. $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
  4868. $textDec='';
  4869. if($this->_flags & self::IS_UNDERLINE)
  4870. $textDec.='underline';
  4871. if($this->_flags & self::IS_OVERLINE)
  4872. $textDec.=' overline';
  4873. if($this->_flags & self::IS_STRIKEOUT)
  4874. $textDec.=' line-through';
  4875. $textDec=ltrim($textDec);
  4876. if($textDec!=='')
  4877. $str.='text-decoration:'.$textDec.';';
  4878. if($this->_size!=='')
  4879. $str.='font-size:'.$this->_size.';';
  4880. if($this->_name!=='')
  4881. $str.='font-family:'.$this->_name.';';
  4882. return $str;
  4883. }
  4884. public function addAttributesToRender($writer)
  4885. {
  4886. if($this->_flags===0)
  4887. return;
  4888. if($this->_flags & self::IS_SET_BOLD)
  4889. $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
  4890. if($this->_flags & self::IS_SET_ITALIC)
  4891. $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
  4892. $textDec='';
  4893. if($this->_flags & self::IS_UNDERLINE)
  4894. $textDec.='underline';
  4895. if($this->_flags & self::IS_OVERLINE)
  4896. $textDec.=' overline';
  4897. if($this->_flags & self::IS_STRIKEOUT)
  4898. $textDec.=' line-through';
  4899. $textDec=ltrim($textDec);
  4900. if($textDec!=='')
  4901. $writer->addStyleAttribute('text-decoration',$textDec);
  4902. if($this->_size!=='')
  4903. $writer->addStyleAttribute('font-size',$this->_size);
  4904. if($this->_name!=='')
  4905. $writer->addStyleAttribute('font-family',$this->_name);
  4906. }
  4907. }
  4908. class TStyle extends TComponent
  4909. {
  4910. private $_fields=array();
  4911. private $_font=null;
  4912. private $_class=null;
  4913. private $_customStyle=null;
  4914. private $_displayStyle='Fixed';
  4915. public function __construct($style=null)
  4916. {
  4917. if($style!==null)
  4918. $this->copyFrom($style);
  4919. }
  4920. public function __clone()
  4921. {
  4922. if($this->_font!==null)
  4923. $this->_font = clone($this->_font);
  4924. }
  4925. public function getBackColor()
  4926. {
  4927. return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
  4928. }
  4929. public function setBackColor($value)
  4930. {
  4931. if(trim($value)==='')
  4932. unset($this->_fields['background-color']);
  4933. else
  4934. $this->_fields['background-color']=$value;
  4935. }
  4936. public function getBorderColor()
  4937. {
  4938. return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
  4939. }
  4940. public function setBorderColor($value)
  4941. {
  4942. if(trim($value)==='')
  4943. unset($this->_fields['border-color']);
  4944. else
  4945. $this->_fields['border-color']=$value;
  4946. }
  4947. public function getBorderStyle()
  4948. {
  4949. return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
  4950. }
  4951. public function setBorderStyle($value)
  4952. {
  4953. if(trim($value)==='')
  4954. unset($this->_fields['border-style']);
  4955. else
  4956. $this->_fields['border-style']=$value;
  4957. }
  4958. public function getBorderWidth()
  4959. {
  4960. return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
  4961. }
  4962. public function setBorderWidth($value)
  4963. {
  4964. if(trim($value)==='')
  4965. unset($this->_fields['border-width']);
  4966. else
  4967. $this->_fields['border-width']=$value;
  4968. }
  4969. public function getCssClass()
  4970. {
  4971. return $this->_class===null?'':$this->_class;
  4972. }
  4973. public function hasCssClass()
  4974. {
  4975. return ($this->_class!==null);
  4976. }
  4977. public function setCssClass($value)
  4978. {
  4979. $this->_class=$value;
  4980. }
  4981. public function getFont()
  4982. {
  4983. if($this->_font===null)
  4984. $this->_font=new TFont;
  4985. return $this->_font;
  4986. }
  4987. public function hasFont()
  4988. {
  4989. return $this->_font !== null;
  4990. }
  4991. public function setDisplayStyle($value)
  4992. {
  4993. $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
  4994. switch($this->_displayStyle)
  4995. {
  4996. case TDisplayStyle::None:
  4997. $this->_fields['display'] = 'none';
  4998. break;
  4999. case TDisplayStyle::Dynamic:
  5000. $this->_fields['display'] = '';
  5001. break;
  5002. case TDisplayStyle::Fixed:
  5003. $this->_fields['visibility'] = 'visible';
  5004. break;
  5005. case TDisplayStyle::Hidden:
  5006. $this->_fields['visibility'] = 'hidden';
  5007. break;
  5008. }
  5009. }
  5010. public function getDisplayStyle()
  5011. {
  5012. return $this->_displayStyle;
  5013. }
  5014. public function getForeColor()
  5015. {
  5016. return isset($this->_fields['color'])?$this->_fields['color']:'';
  5017. }
  5018. public function setForeColor($value)
  5019. {
  5020. if(trim($value)==='')
  5021. unset($this->_fields['color']);
  5022. else
  5023. $this->_fields['color']=$value;
  5024. }
  5025. public function getHeight()
  5026. {
  5027. return isset($this->_fields['height'])?$this->_fields['height']:'';
  5028. }
  5029. public function setHeight($value)
  5030. {
  5031. if(trim($value)==='')
  5032. unset($this->_fields['height']);
  5033. else
  5034. $this->_fields['height']=$value;
  5035. }
  5036. public function getCustomStyle()
  5037. {
  5038. return $this->_customStyle===null?'':$this->_customStyle;
  5039. }
  5040. public function setCustomStyle($value)
  5041. {
  5042. $this->_customStyle=$value;
  5043. }
  5044. public function getStyleField($name)
  5045. {
  5046. return isset($this->_fields[$name])?$this->_fields[$name]:'';
  5047. }
  5048. public function setStyleField($name,$value)
  5049. {
  5050. $this->_fields[$name]=$value;
  5051. }
  5052. public function clearStyleField($name)
  5053. {
  5054. unset($this->_fields[$name]);
  5055. }
  5056. public function hasStyleField($name)
  5057. {
  5058. return isset($this->_fields[$name]);
  5059. }
  5060. public function getWidth()
  5061. {
  5062. return isset($this->_fields['width'])?$this->_fields['width']:'';
  5063. }
  5064. public function setWidth($value)
  5065. {
  5066. $this->_fields['width']=$value;
  5067. }
  5068. public function reset()
  5069. {
  5070. $this->_fields=array();
  5071. $this->_font=null;
  5072. $this->_class=null;
  5073. $this->_customStyle=null;
  5074. }
  5075. public function copyFrom($style)
  5076. {
  5077. if($style instanceof TStyle)
  5078. {
  5079. $this->_fields=array_merge($this->_fields,$style->_fields);
  5080. if($style->_class!==null)
  5081. $this->_class=$style->_class;
  5082. if($style->_customStyle!==null)
  5083. $this->_customStyle=$style->_customStyle;
  5084. if($style->_font!==null)
  5085. $this->getFont()->copyFrom($style->_font);
  5086. }
  5087. }
  5088. public function mergeWith($style)
  5089. {
  5090. if($style instanceof TStyle)
  5091. {
  5092. $this->_fields=array_merge($style->_fields,$this->_fields);
  5093. if($this->_class===null)
  5094. $this->_class=$style->_class;
  5095. if($this->_customStyle===null)
  5096. $this->_customStyle=$style->_customStyle;
  5097. if($style->_font!==null)
  5098. $this->getFont()->mergeWith($style->_font);
  5099. }
  5100. }
  5101. public function addAttributesToRender($writer)
  5102. {
  5103. if($this->_customStyle!==null)
  5104. {
  5105. foreach(explode(';',$this->_customStyle) as $style)
  5106. {
  5107. $arr=explode(':',$style);
  5108. if(isset($arr[1]) && trim($arr[0])!=='')
  5109. $writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
  5110. }
  5111. }
  5112. $writer->addStyleAttributes($this->_fields);
  5113. if($this->_font!==null)
  5114. $this->_font->addAttributesToRender($writer);
  5115. if($this->_class!==null)
  5116. $writer->addAttribute('class',$this->_class);
  5117. }
  5118. public function getStyleFields()
  5119. {
  5120. return $this->_fields;
  5121. }
  5122. }
  5123. class TDisplayStyle extends TEnumerable
  5124. {
  5125. const None='None';
  5126. const Dynamic='Dynamic';
  5127. const Fixed='Fixed';
  5128. const Hidden='Hidden';
  5129. }
  5130. class TTableStyle extends TStyle
  5131. {
  5132. private $_backImageUrl=null;
  5133. private $_horizontalAlign=null;
  5134. private $_cellPadding=null;
  5135. private $_cellSpacing=null;
  5136. private $_gridLines=null;
  5137. private $_borderCollapse=null;
  5138. public function reset()
  5139. {
  5140. $this->_backImageUrl=null;
  5141. $this->_horizontalAlign=null;
  5142. $this->_cellPadding=null;
  5143. $this->_cellSpacing=null;
  5144. $this->_gridLines=null;
  5145. $this->_borderCollapse=null;
  5146. }
  5147. public function copyFrom($style)
  5148. {
  5149. parent::copyFrom($style);
  5150. if($style instanceof TTableStyle)
  5151. {
  5152. if($style->_backImageUrl!==null)
  5153. $this->_backImageUrl=$style->_backImageUrl;
  5154. if($style->_horizontalAlign!==null)
  5155. $this->_horizontalAlign=$style->_horizontalAlign;
  5156. if($style->_cellPadding!==null)
  5157. $this->_cellPadding=$style->_cellPadding;
  5158. if($style->_cellSpacing!==null)
  5159. $this->_cellSpacing=$style->_cellSpacing;
  5160. if($style->_gridLines!==null)
  5161. $this->_gridLines=$style->_gridLines;
  5162. if($style->_borderCollapse!==null)
  5163. $this->_borderCollapse=$style->_borderCollapse;
  5164. }
  5165. }
  5166. public function mergeWith($style)
  5167. {
  5168. parent::mergeWith($style);
  5169. if($style instanceof TTableStyle)
  5170. {
  5171. if($this->_backImageUrl===null && $style->_backImageUrl!==null)
  5172. $this->_backImageUrl=$style->_backImageUrl;
  5173. if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
  5174. $this->_horizontalAlign=$style->_horizontalAlign;
  5175. if($this->_cellPadding===null && $style->_cellPadding!==null)
  5176. $this->_cellPadding=$style->_cellPadding;
  5177. if($this->_cellSpacing===null && $style->_cellSpacing!==null)
  5178. $this->_cellSpacing=$style->_cellSpacing;
  5179. if($this->_gridLines===null && $style->_gridLines!==null)
  5180. $this->_gridLines=$style->_gridLines;
  5181. if($this->_borderCollapse===null && $style->_borderCollapse!==null)
  5182. $this->_borderCollapse=$style->_borderCollapse;
  5183. }
  5184. }
  5185. public function addAttributesToRender($writer)
  5186. {
  5187. if(($url=trim($this->getBackImageUrl()))!=='')
  5188. $writer->addStyleAttribute('background-image','url('.$url.')');
  5189. if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
  5190. $writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
  5191. if(($cellPadding=$this->getCellPadding())>=0)
  5192. $writer->addAttribute('cellpadding',"$cellPadding");
  5193. if(($cellSpacing=$this->getCellSpacing())>=0)
  5194. $writer->addAttribute('cellspacing',"$cellSpacing");
  5195. if($this->getBorderCollapse())
  5196. $writer->addStyleAttribute('border-collapse','collapse');
  5197. switch($this->getGridLines())
  5198. {
  5199. case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
  5200. case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
  5201. case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
  5202. }
  5203. parent::addAttributesToRender($writer);
  5204. }
  5205. public function getBackImageUrl()
  5206. {
  5207. return $this->_backImageUrl===null?'':$this->_backImageUrl;
  5208. }
  5209. public function setBackImageUrl($value)
  5210. {
  5211. $this->_backImageUrl=$value;
  5212. }
  5213. public function getHorizontalAlign()
  5214. {
  5215. return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
  5216. }
  5217. public function setHorizontalAlign($value)
  5218. {
  5219. $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
  5220. }
  5221. public function getCellPadding()
  5222. {
  5223. return $this->_cellPadding===null?-1:$this->_cellPadding;
  5224. }
  5225. public function setCellPadding($value)
  5226. {
  5227. if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
  5228. throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
  5229. }
  5230. public function getCellSpacing()
  5231. {
  5232. return $this->_cellSpacing===null?-1:$this->_cellSpacing;
  5233. }
  5234. public function setCellSpacing($value)
  5235. {
  5236. if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
  5237. throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
  5238. }
  5239. public function getGridLines()
  5240. {
  5241. return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
  5242. }
  5243. public function setGridLines($value)
  5244. {
  5245. $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
  5246. }
  5247. public function getBorderCollapse()
  5248. {
  5249. return $this->_borderCollapse===null?false:$this->_borderCollapse;
  5250. }
  5251. public function setBorderCollapse($value)
  5252. {
  5253. $this->_borderCollapse=TPropertyValue::ensureBoolean($value);
  5254. }
  5255. }
  5256. class TTableItemStyle extends TStyle
  5257. {
  5258. private $_horizontalAlign=null;
  5259. private $_verticalAlign=null;
  5260. private $_wrap=null;
  5261. public function reset()
  5262. {
  5263. parent::reset();
  5264. $this->_verticalAlign=null;
  5265. $this->_horizontalAlign=null;
  5266. $this->_wrap=null;
  5267. }
  5268. public function copyFrom($style)
  5269. {
  5270. parent::copyFrom($style);
  5271. if($style instanceof TTableItemStyle)
  5272. {
  5273. if($this->_verticalAlign===null && $style->_verticalAlign!==null)
  5274. $this->_verticalAlign=$style->_verticalAlign;
  5275. if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
  5276. $this->_horizontalAlign=$style->_horizontalAlign;
  5277. if($this->_wrap===null && $style->_wrap!==null)
  5278. $this->_wrap=$style->_wrap;
  5279. }
  5280. }
  5281. public function mergeWith($style)
  5282. {
  5283. parent::mergeWith($style);
  5284. if($style instanceof TTableItemStyle)
  5285. {
  5286. if($style->_verticalAlign!==null)
  5287. $this->_verticalAlign=$style->_verticalAlign;
  5288. if($style->_horizontalAlign!==null)
  5289. $this->_horizontalAlign=$style->_horizontalAlign;
  5290. if($style->_wrap!==null)
  5291. $this->_wrap=$style->_wrap;
  5292. }
  5293. }
  5294. public function addAttributesToRender($writer)
  5295. {
  5296. if(!$this->getWrap())
  5297. $writer->addStyleAttribute('white-space','nowrap');
  5298. if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
  5299. $writer->addAttribute('align',strtolower($horizontalAlign));
  5300. if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
  5301. $writer->addAttribute('valign',strtolower($verticalAlign));
  5302. parent::addAttributesToRender($writer);
  5303. }
  5304. public function getHorizontalAlign()
  5305. {
  5306. return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
  5307. }
  5308. public function setHorizontalAlign($value)
  5309. {
  5310. $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
  5311. }
  5312. public function getVerticalAlign()
  5313. {
  5314. return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
  5315. }
  5316. public function setVerticalAlign($value)
  5317. {
  5318. $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
  5319. }
  5320. public function getWrap()
  5321. {
  5322. return $this->_wrap===null?true:$this->_wrap;
  5323. }
  5324. public function setWrap($value)
  5325. {
  5326. $this->_wrap=TPropertyValue::ensureBoolean($value);
  5327. }
  5328. }
  5329. class THorizontalAlign extends TEnumerable
  5330. {
  5331. const NotSet='NotSet';
  5332. const Left='Left';
  5333. const Right='Right';
  5334. const Center='Center';
  5335. const Justify='Justify';
  5336. }
  5337. class TVerticalAlign extends TEnumerable
  5338. {
  5339. const NotSet='NotSet';
  5340. const Top='Top';
  5341. const Bottom='Bottom';
  5342. const Middle='Middle';
  5343. }
  5344. class TTableGridLines extends TEnumerable
  5345. {
  5346. const None='None';
  5347. const Horizontal='Horizontal';
  5348. const Vertical='Vertical';
  5349. const Both='Both';
  5350. }
  5351. class TWebControlAdapter extends TControlAdapter
  5352. {
  5353. public function render($writer)
  5354. {
  5355. $this->renderBeginTag($writer);
  5356. $this->renderContents($writer);
  5357. $this->renderEndTag($writer);
  5358. }
  5359. public function renderBeginTag($writer)
  5360. {
  5361. $this->getControl()->renderBeginTag($writer);
  5362. }
  5363. public function renderContents($writer)
  5364. {
  5365. $this->getControl()->renderContents($writer);
  5366. }
  5367. public function renderEndTag($writer)
  5368. {
  5369. $this->getControl()->renderEndTag($writer);
  5370. }
  5371. }
  5372. class TWebControl extends TControl implements IStyleable
  5373. {
  5374. public function copyBaseAttributes(TWebControl $control)
  5375. {
  5376. $this->setAccessKey($control->getAccessKey());
  5377. $this->setToolTip($control->getToolTip());
  5378. $this->setTabIndex($control->getTabIndex());
  5379. if(!$control->getEnabled())
  5380. $this->setEnabled(false);
  5381. if($control->getHasAttributes())
  5382. $this->getAttributes()->copyFrom($control->getAttributes());
  5383. }
  5384. public function getAccessKey()
  5385. {
  5386. return $this->getViewState('AccessKey','');
  5387. }
  5388. public function setAccessKey($value)
  5389. {
  5390. if(strlen($value)>1)
  5391. throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
  5392. $this->setViewState('AccessKey',$value,'');
  5393. }
  5394. public function getBackColor()
  5395. {
  5396. if($style=$this->getViewState('Style',null))
  5397. return $style->getBackColor();
  5398. else
  5399. return '';
  5400. }
  5401. public function setBackColor($value)
  5402. {
  5403. $this->getStyle()->setBackColor($value);
  5404. }
  5405. public function getBorderColor()
  5406. {
  5407. if($style=$this->getViewState('Style',null))
  5408. return $style->getBorderColor();
  5409. else
  5410. return '';
  5411. }
  5412. public function setBorderColor($value)
  5413. {
  5414. $this->getStyle()->setBorderColor($value);
  5415. }
  5416. public function getBorderStyle()
  5417. {
  5418. if($style=$this->getViewState('Style',null))
  5419. return $style->getBorderStyle();
  5420. else
  5421. return '';
  5422. }
  5423. public function setBorderStyle($value)
  5424. {
  5425. $this->getStyle()->setBorderStyle($value);
  5426. }
  5427. public function getBorderWidth()
  5428. {
  5429. if($style=$this->getViewState('Style',null))
  5430. return $style->getBorderWidth();
  5431. else
  5432. return '';
  5433. }
  5434. public function setBorderWidth($value)
  5435. {
  5436. $this->getStyle()->setBorderWidth($value);
  5437. }
  5438. public function getFont()
  5439. {
  5440. return $this->getStyle()->getFont();
  5441. }
  5442. public function getForeColor()
  5443. {
  5444. if($style=$this->getViewState('Style',null))
  5445. return $style->getForeColor();
  5446. else
  5447. return '';
  5448. }
  5449. public function setForeColor($value)
  5450. {
  5451. $this->getStyle()->setForeColor($value);
  5452. }
  5453. public function getHeight()
  5454. {
  5455. if($style=$this->getViewState('Style',null))
  5456. return $style->getHeight();
  5457. else
  5458. return '';
  5459. }
  5460. public function setDisplay($value)
  5461. {
  5462. $this->getStyle()->setDisplayStyle($value);
  5463. }
  5464. public function getDisplay()
  5465. {
  5466. return $this->getStyle()->getDisplayStyle();
  5467. }
  5468. public function setCssClass($value)
  5469. {
  5470. $this->getStyle()->setCssClass($value);
  5471. }
  5472. public function getCssClass()
  5473. {
  5474. if($style=$this->getViewState('Style',null))
  5475. return $style->getCssClass();
  5476. else
  5477. return '';
  5478. }
  5479. public function setHeight($value)
  5480. {
  5481. $this->getStyle()->setHeight($value);
  5482. }
  5483. public function getHasStyle()
  5484. {
  5485. return $this->getViewState('Style',null)!==null;
  5486. }
  5487. protected function createStyle()
  5488. {
  5489. return new TStyle;
  5490. }
  5491. public function getStyle()
  5492. {
  5493. if($style=$this->getViewState('Style',null))
  5494. return $style;
  5495. else
  5496. {
  5497. $style=$this->createStyle();
  5498. $this->setViewState('Style',$style,null);
  5499. return $style;
  5500. }
  5501. }
  5502. public function setStyle($value)
  5503. {
  5504. if(is_string($value))
  5505. $this->getStyle()->setCustomStyle($value);
  5506. else
  5507. throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
  5508. }
  5509. public function clearStyle()
  5510. {
  5511. $this->clearViewState('Style');
  5512. }
  5513. public function getTabIndex()
  5514. {
  5515. return $this->getViewState('TabIndex',0);
  5516. }
  5517. public function setTabIndex($value)
  5518. {
  5519. $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
  5520. }
  5521. protected function getTagName()
  5522. {
  5523. return 'span';
  5524. }
  5525. public function getToolTip()
  5526. {
  5527. return $this->getViewState('ToolTip','');
  5528. }
  5529. public function setToolTip($value)
  5530. {
  5531. $this->setViewState('ToolTip',$value,'');
  5532. }
  5533. public function getWidth()
  5534. {
  5535. if($style=$this->getViewState('Style',null))
  5536. return $style->getWidth();
  5537. else
  5538. return '';
  5539. }
  5540. public function setWidth($value)
  5541. {
  5542. $this->getStyle()->setWidth($value);
  5543. }
  5544. protected function addAttributesToRender($writer)
  5545. {
  5546. if($this->getID()!=='')
  5547. $writer->addAttribute('id',$this->getClientID());
  5548. if(($accessKey=$this->getAccessKey())!=='')
  5549. $writer->addAttribute('accesskey',$accessKey);
  5550. if(!$this->getEnabled())
  5551. $writer->addAttribute('disabled','disabled');
  5552. if(($tabIndex=$this->getTabIndex())>0)
  5553. $writer->addAttribute('tabindex',"$tabIndex");
  5554. if(($toolTip=$this->getToolTip())!=='')
  5555. $writer->addAttribute('title',$toolTip);
  5556. if($style=$this->getViewState('Style',null))
  5557. $style->addAttributesToRender($writer);
  5558. if($this->getHasAttributes())
  5559. {
  5560. foreach($this->getAttributes() as $name=>$value)
  5561. $writer->addAttribute($name,$value);
  5562. }
  5563. }
  5564. public function render($writer)
  5565. {
  5566. $this->renderBeginTag($writer);
  5567. $this->renderContents($writer);
  5568. $this->renderEndTag($writer);
  5569. }
  5570. public function renderBeginTag($writer)
  5571. {
  5572. $this->addAttributesToRender($writer);
  5573. $writer->renderBeginTag($this->getTagName());
  5574. }
  5575. public function renderContents($writer)
  5576. {
  5577. parent::renderChildren($writer);
  5578. }
  5579. public function renderEndTag($writer)
  5580. {
  5581. $writer->renderEndTag();
  5582. }
  5583. }
  5584. class TCompositeControl extends TControl implements INamingContainer
  5585. {
  5586. protected function initRecursive($namingContainer=null)
  5587. {
  5588. $this->ensureChildControls();
  5589. parent::initRecursive($namingContainer);
  5590. }
  5591. }
  5592. class TTemplateControl extends TCompositeControl
  5593. {
  5594. const EXT_TEMPLATE='.tpl';
  5595. private static $_template=array();
  5596. private $_localTemplate=null;
  5597. private $_master=null;
  5598. private $_masterClass='';
  5599. private $_contents=array();
  5600. private $_placeholders=array();
  5601. public function getTemplate()
  5602. {
  5603. if($this->_localTemplate===null)
  5604. {
  5605. $class=get_class($this);
  5606. if(!isset(self::$_template[$class]))
  5607. self::$_template[$class]=$this->loadTemplate();
  5608. return self::$_template[$class];
  5609. }
  5610. else
  5611. return $this->_localTemplate;
  5612. }
  5613. public function setTemplate($value)
  5614. {
  5615. $this->_localTemplate=$value;
  5616. }
  5617. public function getIsSourceTemplateControl()
  5618. {
  5619. if(($template=$this->getTemplate())!==null)
  5620. return $template->getIsSourceTemplate();
  5621. else
  5622. return false;
  5623. }
  5624. public function getTemplateDirectory()
  5625. {
  5626. if(($template=$this->getTemplate())!==null)
  5627. return $template->getContextPath();
  5628. else
  5629. return '';
  5630. }
  5631. protected function loadTemplate()
  5632. {
  5633. $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
  5634. return $template;
  5635. }
  5636. public function createChildControls()
  5637. {
  5638. if($tpl=$this->getTemplate())
  5639. {
  5640. foreach($tpl->getDirective() as $name=>$value)
  5641. {
  5642. if(is_string($value))
  5643. $this->setSubProperty($name,$value);
  5644. else
  5645. throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
  5646. }
  5647. $tpl->instantiateIn($this);
  5648. }
  5649. }
  5650. public function registerContent($id,TContent $object)
  5651. {
  5652. if(isset($this->_contents[$id]))
  5653. throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
  5654. else
  5655. $this->_contents[$id]=$object;
  5656. }
  5657. public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
  5658. {
  5659. if(isset($this->_placeholders[$id]))
  5660. throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
  5661. else
  5662. $this->_placeholders[$id]=$object;
  5663. }
  5664. public function getMasterClass()
  5665. {
  5666. return $this->_masterClass;
  5667. }
  5668. public function setMasterClass($value)
  5669. {
  5670. $this->_masterClass=$value;
  5671. }
  5672. public function getMaster()
  5673. {
  5674. return $this->_master;
  5675. }
  5676. public function injectContent($id,$content)
  5677. {
  5678. if(isset($this->_placeholders[$id]))
  5679. {
  5680. $placeholder=$this->_placeholders[$id];
  5681. $controls=$placeholder->getParent()->getControls();
  5682. $loc=$controls->remove($placeholder);
  5683. $controls->insertAt($loc,$content);
  5684. }
  5685. else
  5686. throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
  5687. }
  5688. protected function initRecursive($namingContainer=null)
  5689. {
  5690. $this->ensureChildControls();
  5691. if($this->_masterClass!=='')
  5692. {
  5693. $master=Prado::createComponent($this->_masterClass);
  5694. if(!($master instanceof TTemplateControl))
  5695. throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
  5696. $this->_master=$master;
  5697. $this->getControls()->clear();
  5698. $this->getControls()->add($master);
  5699. $master->ensureChildControls();
  5700. foreach($this->_contents as $id=>$content)
  5701. $master->injectContent($id,$content);
  5702. }
  5703. else if(!empty($this->_contents))
  5704. throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
  5705. parent::initRecursive($namingContainer);
  5706. }
  5707. }
  5708. class TForm extends TControl
  5709. {
  5710. public function onInit($param)
  5711. {
  5712. parent::onInit($param);
  5713. $this->getPage()->setForm($this);
  5714. }
  5715. protected function addAttributesToRender($writer)
  5716. {
  5717. $writer->addAttribute('id',$this->getClientID());
  5718. $writer->addAttribute('method',$this->getMethod());
  5719. $uri=$this->getRequest()->getRequestURI();
  5720. $writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
  5721. if(($enctype=$this->getEnctype())!=='')
  5722. $writer->addAttribute('enctype',$enctype);
  5723. $attributes=$this->getAttributes();
  5724. $attributes->remove('action');
  5725. $writer->addAttributes($attributes);
  5726. if(($butt=$this->getDefaultButton())!=='')
  5727. {
  5728. if(($button=$this->findControl($butt))!==null)
  5729. $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
  5730. else
  5731. throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
  5732. }
  5733. }
  5734. public function render($writer)
  5735. {
  5736. $page=$this->getPage();
  5737. $page->beginFormRender($writer);
  5738. $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
  5739. $this->renderChildren( $htmlWriter );
  5740. $content = $htmlWriter->flush();
  5741. $page->endFormRender($writer);
  5742. $this->addAttributesToRender($writer);
  5743. $writer->renderBeginTag('form');
  5744. $cs=$page->getClientScript();
  5745. if($page->getClientSupportsJavaScript())
  5746. {
  5747. $cs->renderHiddenFields($writer);
  5748. $cs->renderScriptFiles($writer);
  5749. $cs->renderBeginScripts($writer);
  5750. $writer->write($content);
  5751. $cs->renderEndScripts($writer);
  5752. }
  5753. else
  5754. {
  5755. $cs->renderHiddenFields($writer);
  5756. $writer->write($content);
  5757. }
  5758. $writer->renderEndTag();
  5759. }
  5760. public function getDefaultButton()
  5761. {
  5762. return $this->getViewState('DefaultButton','');
  5763. }
  5764. public function setDefaultButton($value)
  5765. {
  5766. $this->setViewState('DefaultButton',$value,'');
  5767. }
  5768. public function getMethod()
  5769. {
  5770. return $this->getViewState('Method','post');
  5771. }
  5772. public function setMethod($value)
  5773. {
  5774. $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
  5775. }
  5776. public function getEnctype()
  5777. {
  5778. return $this->getViewState('Enctype','');
  5779. }
  5780. public function setEnctype($value)
  5781. {
  5782. $this->setViewState('Enctype',$value,'');
  5783. }
  5784. public function getName()
  5785. {
  5786. return $this->getUniqueID();
  5787. }
  5788. }
  5789. class TClientScriptManager extends TApplicationComponent
  5790. {
  5791. const SCRIPT_PATH='Web/Javascripts/source';
  5792. const SCRIPT_LOADER='Web/Javascripts/clientscripts.php';
  5793. protected $_page;
  5794. private $_hiddenFields=array();
  5795. private $_beginScripts=array();
  5796. private $_endScripts=array();
  5797. private $_scriptFiles=array();
  5798. private $_headScriptFiles=array();
  5799. private $_headScripts=array();
  5800. private $_styleSheetFiles=array();
  5801. private $_styleSheets=array();
  5802. private $_registeredPradoScripts=array();
  5803. private static $_pradoScripts;
  5804. private static $_pradoPackages;
  5805. public function __construct(TPage $owner)
  5806. {
  5807. $this->_page=$owner;
  5808. }
  5809. public function getRequiresHead()
  5810. {
  5811. return count($this->_styleSheetFiles) || count($this->_styleSheets)
  5812. || count($this->_headScriptFiles) || count($this->_headScripts);
  5813. }
  5814. public function registerPradoScript($name)
  5815. {
  5816. $this->registerPradoScriptInternal($name);
  5817. $params=func_get_args();
  5818. $this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
  5819. }
  5820. private function registerPradoScriptInternal($name)
  5821. {
  5822. if(!isset($this->_registeredPradoScripts[$name]))
  5823. {
  5824. if(self::$_pradoScripts === null)
  5825. {
  5826. $packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH.'/packages.php';
  5827. list($packages,$deps)= include($packageFile);
  5828. self::$_pradoScripts = $deps;
  5829. self::$_pradoPackages = $packages;
  5830. }
  5831. if(isset(self::$_pradoScripts[$name]))
  5832. $this->_registeredPradoScripts[$name]=true;
  5833. else
  5834. throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
  5835. }
  5836. }
  5837. public function getPradoScriptAssetUrl()
  5838. {
  5839. $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
  5840. $assets = Prado::getApplication()->getAssetManager();
  5841. return $assets->getPublishedUrl($base);
  5842. }
  5843. protected function renderPradoScripts($writer)
  5844. {
  5845. if(($packages=array_keys($this->_registeredPradoScripts))!==array())
  5846. {
  5847. if (Prado::getApplication()->getMode()!==TApplicationMode::Debug)
  5848. {
  5849. $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
  5850. $url = $this->registerJavascriptPackages($base, $packages);
  5851. $writer->write(TJavaScript::renderScriptFile($url));
  5852. }
  5853. else
  5854. {
  5855. $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
  5856. list($path,$baseUrl)=$this->getPackagePathUrl($base);
  5857. $packagesUrl=array();
  5858. foreach ($packages as $p)
  5859. {
  5860. foreach (self::$_pradoScripts[$p] as $dep)
  5861. {
  5862. foreach (self::$_pradoPackages[$dep] as $script)
  5863. {
  5864. if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
  5865. $packagesUrl[]=$url;
  5866. }
  5867. }
  5868. }
  5869. $writer->write(TJavaScript::renderScriptFiles($packagesUrl));
  5870. }
  5871. }
  5872. }
  5873. public function registerJavascriptPackages($base, $packages, $debug=null, $gzip=true)
  5874. {
  5875. list($path,$url) = $this->getPackagePathUrl($base);
  5876. $scriptLoaderPath = $path.'/'.basename(self::SCRIPT_LOADER);
  5877. $scriptLoaderSrc = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_LOADER;
  5878. if(!is_file($scriptLoaderPath))
  5879. {
  5880. copy($scriptLoaderSrc, $scriptLoaderPath);
  5881. chmod($scriptLoaderPath, PRADO_CHMOD);
  5882. }
  5883. $url .= '/'.basename(self::SCRIPT_LOADER).'?js='.implode(',', $packages);
  5884. if($debug!==false && $this->getApplication()->getMode()===TApplicationMode::Debug)
  5885. {
  5886. $this->verifyJavascriptPackages($base,$path,$packages);
  5887. $url.='&amp;mode=debug';
  5888. }
  5889. if($gzip===false)
  5890. $url.='&amp;gzip=false';
  5891. return $url;
  5892. }
  5893. protected function verifyJavascriptPackages($base,$path,$scripts)
  5894. {
  5895. $file = $path.'/packages.php';
  5896. if(is_file($file))
  5897. {
  5898. list($packs,$deps) = include($file);
  5899. if(count($missing = array_diff($scripts, array_keys($deps))) > 0)
  5900. {
  5901. throw new TConfigurationException('csmanager_invalid_packages',
  5902. $base.'/packages.php',implode(', ', $missing), implode(', ', array_keys($deps)));
  5903. }
  5904. }
  5905. }
  5906. protected function getPackagePathUrl($base)
  5907. {
  5908. $assets = Prado::getApplication()->getAssetManager();
  5909. if(strpos($base, $assets->getBaseUrl())===false)
  5910. {
  5911. if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
  5912. $base = $dir;
  5913. }
  5914. return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
  5915. }
  5916. else
  5917. {
  5918. return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
  5919. }
  5920. }
  5921. public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
  5922. {
  5923. $options = !is_array($options) ? array() : $options;
  5924. $class = new TReflectionClass($callbackHandler);
  5925. $clientSide = $callbackHandler->getActiveControl()->getClientSide();
  5926. $options = array_merge($options, $clientSide->getOptions()->toArray());
  5927. $optionString = TJavaScript::encode($options);
  5928. $this->registerPradoScriptInternal('ajax');
  5929. $id = $callbackHandler->getUniqueID();
  5930. return "new Prado.CallbackRequest('{$id}',{$optionString})";
  5931. }
  5932. public function registerCallbackControl($class, $options)
  5933. {
  5934. $optionString=TJavaScript::encode($options);
  5935. $code="new {$class}({$optionString});";
  5936. $this->_endScripts[sprintf('%08X', crc32($code))]=$code;
  5937. $this->registerPradoScriptInternal('ajax');
  5938. $params=func_get_args();
  5939. $this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
  5940. }
  5941. public function registerPostBackControl($class,$options)
  5942. {
  5943. if($class === null) {
  5944. return;
  5945. }
  5946. if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
  5947. $options['FormID']=$form->getClientID();
  5948. $optionString=TJavaScript::encode($options);
  5949. $code="new {$class}({$optionString});";
  5950. $this->_endScripts[sprintf('%08X', crc32($code))]=$code;
  5951. $this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]='';
  5952. $this->_hiddenFields[TPage::FIELD_POSTBACK_PARAMETER]='';
  5953. $this->registerPradoScriptInternal('prado');
  5954. $params=func_get_args();
  5955. $this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
  5956. }
  5957. public function registerDefaultButton($panel, $button)
  5958. {
  5959. $panelID=is_string($panel)?$panel:$panel->getUniqueID();
  5960. if(is_string($button))
  5961. $buttonID=$button;
  5962. else
  5963. {
  5964. $button->setIsDefaultButton(true);
  5965. $buttonID=$button->getUniqueID();
  5966. }
  5967. $options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
  5968. $code = "new Prado.WebUI.DefaultButton($options);";
  5969. $this->_endScripts['prado:'.$panelID]=$code;
  5970. $this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]='';
  5971. $this->registerPradoScriptInternal('prado');
  5972. $params=array($panelID,$buttonID);
  5973. $this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
  5974. }
  5975. protected function getDefaultButtonOptions($panelID, $buttonID)
  5976. {
  5977. $options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
  5978. $options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
  5979. $options['EventTarget'] = $buttonID;
  5980. $options['Event'] = 'click';
  5981. return $options;
  5982. }
  5983. public function registerFocusControl($target)
  5984. {
  5985. $this->registerPradoScriptInternal('effects');
  5986. if($target instanceof TControl)
  5987. $target=$target->getClientID();
  5988. $id = TJavaScript::quoteString($target);
  5989. $this->_endScripts['prado:focus'] = 'new Effect.ScrollTo("'.$id.'"); Prado.Element.focus("'.$id.'");';
  5990. $params=func_get_args();
  5991. $this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
  5992. }
  5993. public function registerStyleSheetFile($key,$url,$media='')
  5994. {
  5995. if($media==='')
  5996. $this->_styleSheetFiles[$key]=$url;
  5997. else
  5998. $this->_styleSheetFiles[$key]=array($url,$media);
  5999. $params=func_get_args();
  6000. $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
  6001. }
  6002. public function registerStyleSheet($key,$css,$media='')
  6003. {
  6004. $this->_styleSheets[$key]=$css;
  6005. $params=func_get_args();
  6006. $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
  6007. }
  6008. public function registerHeadScriptFile($key,$url)
  6009. {
  6010. $this->_headScriptFiles[$key]=$url;
  6011. $params=func_get_args();
  6012. $this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
  6013. }
  6014. public function registerHeadScript($key,$script)
  6015. {
  6016. $this->_headScripts[$key]=$script;
  6017. $params=func_get_args();
  6018. $this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
  6019. }
  6020. public function registerScriptFile($key,$url)
  6021. {
  6022. $this->_scriptFiles[$key]=$url;
  6023. $params=func_get_args();
  6024. $this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
  6025. }
  6026. public function registerBeginScript($key,$script)
  6027. {
  6028. $this->_beginScripts[$key]=$script;
  6029. $params=func_get_args();
  6030. $this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
  6031. }
  6032. public function registerEndScript($key,$script)
  6033. {
  6034. $this->_endScripts[$key]=$script;
  6035. $params=func_get_args();
  6036. $this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
  6037. }
  6038. public function registerHiddenField($name,$value)
  6039. {
  6040. $this->_hiddenFields[$name]=$value;
  6041. $params=func_get_args();
  6042. $this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
  6043. }
  6044. public function isStyleSheetFileRegistered($key)
  6045. {
  6046. return isset($this->_styleSheetFiles[$key]);
  6047. }
  6048. public function isStyleSheetRegistered($key)
  6049. {
  6050. return isset($this->_styleSheets[$key]);
  6051. }
  6052. public function isHeadScriptFileRegistered($key)
  6053. {
  6054. return isset($this->_headScriptFiles[$key]);
  6055. }
  6056. public function isHeadScriptRegistered($key)
  6057. {
  6058. return isset($this->_headScripts[$key]);
  6059. }
  6060. public function isScriptFileRegistered($key)
  6061. {
  6062. return isset($this->_scriptFiles[$key]);
  6063. }
  6064. public function isBeginScriptRegistered($key)
  6065. {
  6066. return isset($this->_beginScripts[$key]);
  6067. }
  6068. public function isEndScriptRegistered($key)
  6069. {
  6070. return isset($this->_endScripts[$key]);
  6071. }
  6072. public function hasEndScripts()
  6073. {
  6074. return count($this->_endScripts) > 0;
  6075. }
  6076. public function hasBeginScripts()
  6077. {
  6078. return count($this->_beginScripts) > 0;
  6079. }
  6080. public function isHiddenFieldRegistered($key)
  6081. {
  6082. return isset($this->_hiddenFields[$key]);
  6083. }
  6084. public function renderStyleSheetFiles($writer)
  6085. {
  6086. $str='';
  6087. foreach($this->_styleSheetFiles as $url)
  6088. {
  6089. if(is_array($url))
  6090. $str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
  6091. else
  6092. $str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
  6093. }
  6094. $writer->write($str);
  6095. }
  6096. public function renderStyleSheets($writer)
  6097. {
  6098. if(count($this->_styleSheets))
  6099. $writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
  6100. }
  6101. public function renderHeadScriptFiles($writer)
  6102. {
  6103. $writer->write(TJavaScript::renderScriptFiles($this->_headScriptFiles));
  6104. }
  6105. public function renderHeadScripts($writer)
  6106. {
  6107. $writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
  6108. }
  6109. public function renderScriptFiles($writer)
  6110. {
  6111. $this->renderPradoScripts($writer);
  6112. if(!empty($this->_scriptFiles))
  6113. $writer->write(TJavaScript::renderScriptFiles($this->_scriptFiles));
  6114. }
  6115. public function renderBeginScripts($writer)
  6116. {
  6117. $writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
  6118. }
  6119. public function renderEndScripts($writer)
  6120. {
  6121. $writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
  6122. }
  6123. public function renderHiddenFields($writer)
  6124. {
  6125. $str='';
  6126. foreach($this->_hiddenFields as $name=>$value)
  6127. {
  6128. $id=strtr($name,':','_');
  6129. if(is_array($value))
  6130. {
  6131. foreach($value as $v)
  6132. $str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
  6133. }
  6134. else
  6135. {
  6136. $str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
  6137. }
  6138. }
  6139. if($str!=='')
  6140. $writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
  6141. }
  6142. }
  6143. abstract class TClientSideOptions extends TComponent
  6144. {
  6145. private $_options;
  6146. public function __construct()
  6147. {
  6148. $this->_options = Prado::createComponent('System.Collections.TMap');
  6149. }
  6150. protected function setFunction($name, $code)
  6151. {
  6152. if(!TJavaScript::isFunction($code))
  6153. $code = TJavaScript::quoteFunction($this->ensureFunction($code));
  6154. $this->setOption($name, $code);
  6155. }
  6156. protected function getOption($name)
  6157. {
  6158. return $this->_options->itemAt($name);
  6159. }
  6160. protected function setOption($name, $value)
  6161. {
  6162. $this->_options->add($name, $value);
  6163. }
  6164. public function getOptions()
  6165. {
  6166. return $this->_options;
  6167. }
  6168. protected function ensureFunction($javascript)
  6169. {
  6170. return "function(sender, parameter){ {$javascript} }";
  6171. }
  6172. }
  6173. class TPage extends TTemplateControl
  6174. {
  6175. const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
  6176. const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
  6177. const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
  6178. const FIELD_PAGESTATE='PRADO_PAGESTATE';
  6179. const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
  6180. const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
  6181. private static $_systemPostFields=array(
  6182. 'PRADO_POSTBACK_TARGET'=>true,
  6183. 'PRADO_POSTBACK_PARAMETER'=>true,
  6184. 'PRADO_LASTFOCUS'=>true,
  6185. 'PRADO_PAGESTATE'=>true,
  6186. 'PRADO_CALLBACK_TARGET'=>true,
  6187. 'PRADO_CALLBACK_PARAMETER'=>true
  6188. );
  6189. private $_form;
  6190. private $_head;
  6191. private $_validators=array();
  6192. private $_validated=false;
  6193. private $_theme;
  6194. private $_title;
  6195. private $_styleSheet;
  6196. protected $_clientScript;
  6197. protected $_postData;
  6198. protected $_restPostData;
  6199. protected $_controlsPostDataChanged=array();
  6200. protected $_controlsRequiringPostData=array();
  6201. protected $_controlsRegisteredForPostData=array();
  6202. private $_postBackEventTarget;
  6203. private $_postBackEventParameter;
  6204. protected $_formRendered=false;
  6205. protected $_inFormRender=false;
  6206. private $_focus;
  6207. private $_pagePath='';
  6208. private $_enableStateValidation=true;
  6209. private $_enableStateEncryption=false;
  6210. private $_enableStateCompression=true;
  6211. private $_statePersisterClass='System.Web.UI.TPageStatePersister';
  6212. private $_statePersister;
  6213. private $_cachingStack;
  6214. private $_clientState='';
  6215. protected $_postDataLoaders=array();
  6216. protected $_isLoadingPostData=false;
  6217. private $_enableJavaScript=true;
  6218. public function __construct()
  6219. {
  6220. parent::__construct();
  6221. $this->setPage($this);
  6222. }
  6223. public function run($writer)
  6224. {
  6225. $this->determinePostBackMode();
  6226. if($this->getIsPostBack())
  6227. {
  6228. if($this->getIsCallback())
  6229. $this->processCallbackRequest($writer);
  6230. else
  6231. $this->processPostBackRequest($writer);
  6232. }
  6233. else
  6234. $this->processNormalRequest($writer);
  6235. }
  6236. protected function processNormalRequest($writer)
  6237. {
  6238. $this->onPreInit(null);
  6239. $this->initRecursive();
  6240. $this->onInitComplete(null);
  6241. $this->onPreLoad(null);
  6242. $this->loadRecursive();
  6243. $this->onLoadComplete(null);
  6244. $this->preRenderRecursive();
  6245. $this->onPreRenderComplete(null);
  6246. $this->savePageState();
  6247. $this->onSaveStateComplete(null);
  6248. $this->renderControl($writer);
  6249. $this->unloadRecursive();
  6250. }
  6251. protected function processPostBackRequest($writer)
  6252. {
  6253. $this->onPreInit(null);
  6254. $this->initRecursive();
  6255. $this->onInitComplete(null);
  6256. $this->_restPostData=new TMap;
  6257. $this->loadPageState();
  6258. $this->processPostData($this->_postData,true);
  6259. $this->onPreLoad(null);
  6260. $this->loadRecursive();
  6261. $this->processPostData($this->_restPostData,false);
  6262. $this->raiseChangedEvents();
  6263. $this->raisePostBackEvent();
  6264. $this->onLoadComplete(null);
  6265. $this->preRenderRecursive();
  6266. $this->onPreRenderComplete(null);
  6267. $this->savePageState();
  6268. $this->onSaveStateComplete(null);
  6269. $this->renderControl($writer);
  6270. $this->unloadRecursive();
  6271. }
  6272. protected function processCallbackRequest($writer)
  6273. {
  6274. Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
  6275. $this->setAdapter(new TActivePageAdapter($this));
  6276. if (($g=$this->getApplication()->getGlobalization(false))!==null &&
  6277. strtoupper($enc=$g->getCharset())!='UTF-8')
  6278. foreach ($this->_postData as $k=>$v)
  6279. $this->_postData[$k]=iconv('UTF-8',$enc.'//IGNORE',$v);
  6280. $this->onPreInit(null);
  6281. $this->initRecursive();
  6282. $this->onInitComplete(null);
  6283. $this->_restPostData=new TMap;
  6284. $this->loadPageState();
  6285. $this->processPostData($this->_postData,true);
  6286. $this->onPreLoad(null);
  6287. $this->loadRecursive();
  6288. $this->processPostData($this->_restPostData,false);
  6289. $this->raiseChangedEvents();
  6290. $this->getAdapter()->processCallbackEvent($writer);
  6291. $this->onLoadComplete(null);
  6292. $this->preRenderRecursive();
  6293. $this->onPreRenderComplete(null);
  6294. $this->savePageState();
  6295. $this->onSaveStateComplete(null);
  6296. $this->getAdapter()->renderCallbackResponse($writer);
  6297. $this->unloadRecursive();
  6298. }
  6299. public function getCallbackClient()
  6300. {
  6301. if($this->getAdapter() !== null)
  6302. return $this->getAdapter()->getCallbackClientHandler();
  6303. else
  6304. return new TCallbackClientScript();
  6305. }
  6306. public function setCallbackClient($client)
  6307. {
  6308. $this->getAdapter()->setCallbackClientHandler($client);
  6309. }
  6310. public function getCallbackEventTarget()
  6311. {
  6312. return $this->getAdapter()->getCallbackEventTarget();
  6313. }
  6314. public function setCallbackEventTarget(TControl $control)
  6315. {
  6316. $this->getAdapter()->setCallbackEventTarget($control);
  6317. }
  6318. public function getCallbackEventParameter()
  6319. {
  6320. return $this->getAdapter()->getCallbackEventParameter();
  6321. }
  6322. public function setCallbackEventParameter($value)
  6323. {
  6324. $this->getAdapter()->setCallbackEventParameter($value);
  6325. }
  6326. public function registerPostDataLoader($control)
  6327. {
  6328. $id=is_string($control)?$control:$control->getUniqueID();
  6329. $this->_postDataLoaders[$id] = true;
  6330. }
  6331. public function getPostDataLoaders()
  6332. {
  6333. return array_keys($this->_postDataLoaders);
  6334. }
  6335. public function getForm()
  6336. {
  6337. return $this->_form;
  6338. }
  6339. public function setForm(TForm $form)
  6340. {
  6341. if($this->_form===null)
  6342. $this->_form=$form;
  6343. else
  6344. throw new TInvalidOperationException('page_form_duplicated');
  6345. }
  6346. public function getValidators($validationGroup=null)
  6347. {
  6348. if(!$this->_validators)
  6349. $this->_validators=new TList;
  6350. if($validationGroup===null)
  6351. return $this->_validators;
  6352. else
  6353. {
  6354. $list=new TList;
  6355. foreach($this->_validators as $validator)
  6356. if($validator->getValidationGroup()===$validationGroup)
  6357. $list->add($validator);
  6358. return $list;
  6359. }
  6360. }
  6361. public function validate($validationGroup=null)
  6362. {
  6363. $this->_validated=true;
  6364. if($this->_validators && $this->_validators->getCount())
  6365. {
  6366. if($validationGroup===null)
  6367. {
  6368. foreach($this->_validators as $validator)
  6369. $validator->validate();
  6370. }
  6371. else
  6372. {
  6373. foreach($this->_validators as $validator)
  6374. {
  6375. if($validator->getValidationGroup()===$validationGroup)
  6376. $validator->validate();
  6377. }
  6378. }
  6379. }
  6380. }
  6381. public function getIsValid()
  6382. {
  6383. if($this->_validated)
  6384. {
  6385. if($this->_validators && $this->_validators->getCount())
  6386. {
  6387. foreach($this->_validators as $validator)
  6388. if(!$validator->getIsValid())
  6389. return false;
  6390. }
  6391. return true;
  6392. }
  6393. else
  6394. throw new TInvalidOperationException('page_isvalid_unknown');
  6395. }
  6396. public function getTheme()
  6397. {
  6398. if(is_string($this->_theme))
  6399. $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
  6400. return $this->_theme;
  6401. }
  6402. public function setTheme($value)
  6403. {
  6404. $this->_theme=empty($value)?null:$value;
  6405. }
  6406. public function getStyleSheetTheme()
  6407. {
  6408. if(is_string($this->_styleSheet))
  6409. $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
  6410. return $this->_styleSheet;
  6411. }
  6412. public function setStyleSheetTheme($value)
  6413. {
  6414. $this->_styleSheet=empty($value)?null:$value;
  6415. }
  6416. public function applyControlSkin($control)
  6417. {
  6418. if(($theme=$this->getTheme())!==null)
  6419. $theme->applySkin($control);
  6420. }
  6421. public function applyControlStyleSheet($control)
  6422. {
  6423. if(($theme=$this->getStyleSheetTheme())!==null)
  6424. $theme->applySkin($control);
  6425. }
  6426. public function getClientScript()
  6427. {
  6428. if(!$this->_clientScript) {
  6429. $className = $classPath = $this->getService()->getClientScriptManagerClass();
  6430. Prado::using($className);
  6431. if(($pos=strrpos($className,'.'))!==false)
  6432. $className=substr($className,$pos+1);
  6433. if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
  6434. throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
  6435. $this->_clientScript=new $className($this);
  6436. }
  6437. return $this->_clientScript;
  6438. }
  6439. public function onPreInit($param)
  6440. {
  6441. $this->raiseEvent('OnPreInit',$this,$param);
  6442. }
  6443. public function onInitComplete($param)
  6444. {
  6445. $this->raiseEvent('OnInitComplete',$this,$param);
  6446. }
  6447. public function onPreLoad($param)
  6448. {
  6449. $this->raiseEvent('OnPreLoad',$this,$param);
  6450. }
  6451. public function onLoadComplete($param)
  6452. {
  6453. $this->raiseEvent('OnLoadComplete',$this,$param);
  6454. }
  6455. public function onPreRenderComplete($param)
  6456. {
  6457. $this->raiseEvent('OnPreRenderComplete',$this,$param);
  6458. $cs=$this->getClientScript();
  6459. $theme=$this->getTheme();
  6460. if($theme instanceof ITheme)
  6461. {
  6462. foreach($theme->getStyleSheetFiles() as $url)
  6463. $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
  6464. foreach($theme->getJavaScriptFiles() as $url)
  6465. $cs->registerHeadScriptFile($url,$url);
  6466. }
  6467. $styleSheet=$this->getStyleSheetTheme();
  6468. if($styleSheet instanceof ITheme)
  6469. {
  6470. foreach($styleSheet->getStyleSheetFiles() as $url)
  6471. $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
  6472. foreach($styleSheet->getJavaScriptFiles() as $url)
  6473. $cs->registerHeadScriptFile($url,$url);
  6474. }
  6475. if($cs->getRequiresHead() && $this->getHead()===null)
  6476. throw new TConfigurationException('page_head_required');
  6477. }
  6478. private function getCssMediaType($url)
  6479. {
  6480. $segs=explode('.',basename($url));
  6481. if(isset($segs[2]))
  6482. return $segs[count($segs)-2];
  6483. else
  6484. return '';
  6485. }
  6486. public function onSaveStateComplete($param)
  6487. {
  6488. $this->raiseEvent('OnSaveStateComplete',$this,$param);
  6489. }
  6490. private function determinePostBackMode()
  6491. {
  6492. $postData=$this->getRequest();
  6493. if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
  6494. $this->_postData=$postData;
  6495. }
  6496. public function getIsPostBack()
  6497. {
  6498. return $this->_postData!==null;
  6499. }
  6500. public function getIsCallback()
  6501. {
  6502. return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
  6503. }
  6504. public function saveState()
  6505. {
  6506. parent::saveState();
  6507. $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
  6508. }
  6509. public function loadState()
  6510. {
  6511. parent::loadState();
  6512. $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
  6513. }
  6514. protected function loadPageState()
  6515. {
  6516. $state=$this->getStatePersister()->load();
  6517. $this->loadStateRecursive($state,$this->getEnableViewState());
  6518. }
  6519. protected function savePageState()
  6520. {
  6521. $state=&$this->saveStateRecursive($this->getEnableViewState());
  6522. $this->getStatePersister()->save($state);
  6523. }
  6524. protected function isSystemPostField($field)
  6525. {
  6526. return isset(self::$_systemPostFields[$field]);
  6527. }
  6528. public function registerRequiresPostData($control)
  6529. {
  6530. $id=is_string($control)?$control:$control->getUniqueID();
  6531. $this->_controlsRegisteredForPostData[$id]=true;
  6532. $this->registerPostDataLoader($id);
  6533. $params=func_get_args();
  6534. foreach($this->getCachingStack() as $item)
  6535. $item->registerAction('Page','registerRequiresPostData',$id);
  6536. }
  6537. public function getPostBackEventTarget()
  6538. {
  6539. if($this->_postBackEventTarget===null && $this->_postData!==null)
  6540. {
  6541. $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
  6542. if(!empty($eventTarget))
  6543. $this->_postBackEventTarget=$this->findControl($eventTarget);
  6544. }
  6545. return $this->_postBackEventTarget;
  6546. }
  6547. public function setPostBackEventTarget(TControl $control)
  6548. {
  6549. $this->_postBackEventTarget=$control;
  6550. }
  6551. public function getPostBackEventParameter()
  6552. {
  6553. if($this->_postBackEventParameter===null && $this->_postData!==null)
  6554. {
  6555. if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
  6556. $this->_postBackEventParameter='';
  6557. }
  6558. return $this->_postBackEventParameter;
  6559. }
  6560. public function setPostBackEventParameter($value)
  6561. {
  6562. $this->_postBackEventParameter=$value;
  6563. }
  6564. protected function processPostData($postData,$beforeLoad)
  6565. {
  6566. $this->_isLoadingPostData=true;
  6567. if($beforeLoad)
  6568. $this->_restPostData=new TMap;
  6569. foreach($postData as $key=>$value)
  6570. {
  6571. if($this->isSystemPostField($key))
  6572. continue;
  6573. else if($control=$this->findControl($key))
  6574. {
  6575. if($control instanceof IPostBackDataHandler)
  6576. {
  6577. if($control->loadPostData($key,$postData))
  6578. $this->_controlsPostDataChanged[]=$control;
  6579. }
  6580. else if($control instanceof IPostBackEventHandler &&
  6581. empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
  6582. {
  6583. $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);
  6584. }
  6585. unset($this->_controlsRequiringPostData[$key]);
  6586. }
  6587. else if($beforeLoad)
  6588. $this->_restPostData->add($key,$value);
  6589. }
  6590. foreach($this->_controlsRequiringPostData as $key=>$value)
  6591. {
  6592. if($control=$this->findControl($key))
  6593. {
  6594. if($control instanceof IPostBackDataHandler)
  6595. {
  6596. if($control->loadPostData($key,$this->_postData))
  6597. $this->_controlsPostDataChanged[]=$control;
  6598. }
  6599. else
  6600. throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
  6601. unset($this->_controlsRequiringPostData[$key]);
  6602. }
  6603. }
  6604. $this->_isLoadingPostData=false;
  6605. }
  6606. public function getIsLoadingPostData()
  6607. {
  6608. return $this->_isLoadingPostData;
  6609. }
  6610. protected function raiseChangedEvents()
  6611. {
  6612. foreach($this->_controlsPostDataChanged as $control)
  6613. $control->raisePostDataChangedEvent();
  6614. }
  6615. protected function raisePostBackEvent()
  6616. {
  6617. if(($postBackHandler=$this->getPostBackEventTarget())===null)
  6618. $this->validate();
  6619. else if($postBackHandler instanceof IPostBackEventHandler)
  6620. $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
  6621. }
  6622. public function ensureRenderInForm($control)
  6623. {
  6624. if(!$this->getIsCallback() && !$this->_inFormRender)
  6625. throw new TConfigurationException('page_control_outofform',get_class($control),$control->getUniqueID());
  6626. }
  6627. public function beginFormRender($writer)
  6628. {
  6629. if($this->_formRendered)
  6630. throw new TConfigurationException('page_form_duplicated');
  6631. $this->_formRendered=true;
  6632. $this->_inFormRender=true;
  6633. $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
  6634. }
  6635. public function endFormRender($writer)
  6636. {
  6637. if($this->_focus)
  6638. {
  6639. if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
  6640. $focus=$this->_focus->getClientID();
  6641. else
  6642. $focus=$this->_focus;
  6643. $this->getClientScript()->registerFocusControl($focus);
  6644. }
  6645. else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
  6646. $this->getClientScript()->registerFocusControl($lastFocus);
  6647. $this->_inFormRender=false;
  6648. }
  6649. public function setFocus($value)
  6650. {
  6651. $this->_focus=$value;
  6652. }
  6653. public function getClientSupportsJavaScript()
  6654. {
  6655. return $this->_enableJavaScript;
  6656. }
  6657. public function setClientSupportsJavaScript($value)
  6658. {
  6659. $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
  6660. }
  6661. public function getHead()
  6662. {
  6663. return $this->_head;
  6664. }
  6665. public function setHead(THead $value)
  6666. {
  6667. if($this->_head)
  6668. throw new TInvalidOperationException('page_head_duplicated');
  6669. $this->_head=$value;
  6670. if($this->_title!==null)
  6671. {
  6672. $this->_head->setTitle($this->_title);
  6673. $this->_title=null;
  6674. }
  6675. }
  6676. public function getTitle()
  6677. {
  6678. if($this->_head)
  6679. return $this->_head->getTitle();
  6680. else
  6681. return $this->_title===null ? '' : $this->_title;
  6682. }
  6683. public function setTitle($value)
  6684. {
  6685. if($this->_head)
  6686. $this->_head->setTitle($value);
  6687. else
  6688. $this->_title=$value;
  6689. }
  6690. public function getClientState()
  6691. {
  6692. return $this->_clientState;
  6693. }
  6694. public function setClientState($state)
  6695. {
  6696. $this->_clientState=$state;
  6697. }
  6698. public function getRequestClientState()
  6699. {
  6700. return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
  6701. }
  6702. public function getStatePersisterClass()
  6703. {
  6704. return $this->_statePersisterClass;
  6705. }
  6706. public function setStatePersisterClass($value)
  6707. {
  6708. $this->_statePersisterClass=$value;
  6709. }
  6710. public function getStatePersister()
  6711. {
  6712. if($this->_statePersister===null)
  6713. {
  6714. $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
  6715. if(!($this->_statePersister instanceof IPageStatePersister))
  6716. throw new TInvalidDataTypeException('page_statepersister_invalid');
  6717. $this->_statePersister->setPage($this);
  6718. }
  6719. return $this->_statePersister;
  6720. }
  6721. public function getEnableStateValidation()
  6722. {
  6723. return $this->_enableStateValidation;
  6724. }
  6725. public function setEnableStateValidation($value)
  6726. {
  6727. $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
  6728. }
  6729. public function getEnableStateEncryption()
  6730. {
  6731. return $this->_enableStateEncryption;
  6732. }
  6733. public function setEnableStateEncryption($value)
  6734. {
  6735. $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
  6736. }
  6737. public function getEnableStateCompression()
  6738. {
  6739. return $this->_enableStateCompression;
  6740. }
  6741. public function setEnableStateCompression($value)
  6742. {
  6743. $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
  6744. }
  6745. public function getPagePath()
  6746. {
  6747. return $this->_pagePath;
  6748. }
  6749. public function setPagePath($value)
  6750. {
  6751. $this->_pagePath=$value;
  6752. }
  6753. public function registerCachingAction($context,$funcName,$funcParams)
  6754. {
  6755. if($this->_cachingStack)
  6756. {
  6757. foreach($this->_cachingStack as $cache)
  6758. $cache->registerAction($context,$funcName,$funcParams);
  6759. }
  6760. }
  6761. public function getCachingStack()
  6762. {
  6763. if(!$this->_cachingStack)
  6764. $this->_cachingStack=new TStack;
  6765. return $this->_cachingStack;
  6766. }
  6767. }
  6768. interface IPageStatePersister
  6769. {
  6770. public function getPage();
  6771. public function setPage(TPage $page);
  6772. public function save($state);
  6773. public function load();
  6774. }
  6775. class TPageStateFormatter
  6776. {
  6777. public static function serialize($page,$data)
  6778. {
  6779. $sm=$page->getApplication()->getSecurityManager();
  6780. if($page->getEnableStateValidation())
  6781. $str=$sm->hashData(Prado::serialize($data));
  6782. else
  6783. $str=Prado::serialize($data);
  6784. if($page->getEnableStateCompression() && extension_loaded('zlib'))
  6785. $str=gzcompress($str);
  6786. if($page->getEnableStateEncryption())
  6787. $str=$sm->encrypt($str);
  6788. return base64_encode($str);
  6789. }
  6790. public static function unserialize($page,$data)
  6791. {
  6792. $str=base64_decode($data);
  6793. if($str==='')
  6794. return null;
  6795. if($str!==false)
  6796. {
  6797. $sm=$page->getApplication()->getSecurityManager();
  6798. if($page->getEnableStateEncryption())
  6799. $str=$sm->decrypt($str);
  6800. if($page->getEnableStateCompression() && extension_loaded('zlib'))
  6801. $str=@gzuncompress($str);
  6802. if($page->getEnableStateValidation())
  6803. {
  6804. if(($str=$sm->validateData($str))!==false)
  6805. return Prado::unserialize($str);
  6806. }
  6807. else
  6808. return Prado::unserialize($str);
  6809. }
  6810. return null;
  6811. }
  6812. }
  6813. class TOutputCache extends TControl implements INamingContainer
  6814. {
  6815. const CACHE_ID_PREFIX='prado:outputcache';
  6816. private $_cacheModuleID='';
  6817. private $_dataCached=false;
  6818. private $_cacheAvailable=false;
  6819. private $_cacheChecked=false;
  6820. private $_cacheKey=null;
  6821. private $_duration=60;
  6822. private $_cache=null;
  6823. private $_contents;
  6824. private $_state;
  6825. private $_actions=array();
  6826. private $_varyByParam='';
  6827. private $_keyPrefix='';
  6828. private $_varyBySession=false;
  6829. private $_cachePostBack=false;
  6830. private $_cacheTime=0;
  6831. public function getAllowChildControls()
  6832. {
  6833. $this->determineCacheability();
  6834. return !$this->_dataCached;
  6835. }
  6836. private function determineCacheability()
  6837. {
  6838. if(!$this->_cacheChecked)
  6839. {
  6840. $this->_cacheChecked=true;
  6841. if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
  6842. {
  6843. if($this->_cacheModuleID!=='')
  6844. {
  6845. $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
  6846. if(!($this->_cache instanceof ICache))
  6847. throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
  6848. }
  6849. else
  6850. $this->_cache=$this->getApplication()->getCache();
  6851. if($this->_cache!==null)
  6852. {
  6853. $this->_cacheAvailable=true;
  6854. $data=$this->_cache->get($this->getCacheKey());
  6855. if(is_array($data))
  6856. {
  6857. $param=new TOutputCacheCheckDependencyEventParameter;
  6858. $param->setCacheTime(isset($data[3])?$data[3]:0);
  6859. $this->onCheckDependency($param);
  6860. $this->_dataCached=$param->getIsValid();
  6861. }
  6862. else
  6863. $this->_dataCached=false;
  6864. if($this->_dataCached)
  6865. list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
  6866. }
  6867. }
  6868. }
  6869. }
  6870. protected function initRecursive($namingContainer=null)
  6871. {
  6872. if($this->_cacheAvailable && !$this->_dataCached)
  6873. {
  6874. $stack=$this->getPage()->getCachingStack();
  6875. $stack->push($this);
  6876. parent::initRecursive($namingContainer);
  6877. $stack->pop();
  6878. }
  6879. else
  6880. parent::initRecursive($namingContainer);
  6881. }
  6882. protected function loadRecursive()
  6883. {
  6884. if($this->_cacheAvailable && !$this->_dataCached)
  6885. {
  6886. $stack=$this->getPage()->getCachingStack();
  6887. $stack->push($this);
  6888. parent::loadRecursive();
  6889. $stack->pop();
  6890. }
  6891. else
  6892. {
  6893. if($this->_dataCached)
  6894. $this->performActions();
  6895. parent::loadRecursive();
  6896. }
  6897. }
  6898. private function performActions()
  6899. {
  6900. $page=$this->getPage();
  6901. $cs=$page->getClientScript();
  6902. foreach($this->_actions as $action)
  6903. {
  6904. if($action[0]==='Page.ClientScript')
  6905. call_user_func_array(array($cs,$action[1]),$action[2]);
  6906. else if($action[0]==='Page')
  6907. call_user_func_array(array($page,$action[1]),$action[2]);
  6908. else
  6909. call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
  6910. }
  6911. }
  6912. protected function preRenderRecursive()
  6913. {
  6914. if($this->_cacheAvailable && !$this->_dataCached)
  6915. {
  6916. $stack=$this->getPage()->getCachingStack();
  6917. $stack->push($this);
  6918. parent::preRenderRecursive();
  6919. $stack->pop();
  6920. }
  6921. else
  6922. parent::preRenderRecursive();
  6923. }
  6924. protected function loadStateRecursive(&$state,$needViewState=true)
  6925. {
  6926. $st=unserialize($state);
  6927. parent::loadStateRecursive($st,$needViewState);
  6928. }
  6929. protected function &saveStateRecursive($needViewState=true)
  6930. {
  6931. if($this->_dataCached)
  6932. return $this->_state;
  6933. else
  6934. {
  6935. $st=parent::saveStateRecursive($needViewState);
  6936. $this->_state=serialize($st);
  6937. return $this->_state;
  6938. }
  6939. }
  6940. public function registerAction($context,$funcName,$funcParams)
  6941. {
  6942. $this->_actions[]=array($context,$funcName,$funcParams);
  6943. }
  6944. private function getCacheKey()
  6945. {
  6946. if($this->_cacheKey===null)
  6947. $this->_cacheKey=$this->calculateCacheKey();
  6948. return $this->_cacheKey;
  6949. }
  6950. protected function calculateCacheKey()
  6951. {
  6952. $key=$this->getBaseCacheKey();
  6953. if($this->_varyBySession)
  6954. $key.=$this->getSession()->getSessionID();
  6955. if($this->_varyByParam!=='')
  6956. {
  6957. $params=array();
  6958. $request=$this->getRequest();
  6959. foreach(explode(',',$this->_varyByParam) as $name)
  6960. {
  6961. $name=trim($name);
  6962. $params[$name]=$request->itemAt($name);
  6963. }
  6964. $key.=serialize($params);
  6965. }
  6966. $param=new TOutputCacheCalculateKeyEventParameter;
  6967. $this->onCalculateKey($param);
  6968. $key.=$param->getCacheKey();
  6969. return $key;
  6970. }
  6971. protected function getBaseCacheKey()
  6972. {
  6973. return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
  6974. }
  6975. public function getCacheModuleID()
  6976. {
  6977. return $this->_cacheModuleID;
  6978. }
  6979. public function setCacheModuleID($value)
  6980. {
  6981. $this->_cacheModuleID=$value;
  6982. }
  6983. public function setCacheKeyPrefix($value)
  6984. {
  6985. $this->_keyPrefix=$value;
  6986. }
  6987. public function getCacheTime()
  6988. {
  6989. return $this->_cacheTime;
  6990. }
  6991. protected function getCacheDependency()
  6992. {
  6993. return null;
  6994. }
  6995. public function getContentCached()
  6996. {
  6997. return $this->_dataCached;
  6998. }
  6999. public function getDuration()
  7000. {
  7001. return $this->_duration;
  7002. }
  7003. public function setDuration($value)
  7004. {
  7005. if(($value=TPropertyValue::ensureInteger($value))<0)
  7006. throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
  7007. $this->_duration=$value;
  7008. }
  7009. public function getVaryByParam()
  7010. {
  7011. return $this->_varyByParam;
  7012. }
  7013. public function setVaryByParam($value)
  7014. {
  7015. $this->_varyByParam=trim($value);
  7016. }
  7017. public function getVaryBySession()
  7018. {
  7019. return $this->_varyBySession;
  7020. }
  7021. public function setVaryBySession($value)
  7022. {
  7023. $this->_varyBySession=TPropertyValue::ensureBoolean($value);
  7024. }
  7025. public function getCachingPostBack()
  7026. {
  7027. return $this->_cachePostBack;
  7028. }
  7029. public function setCachingPostBack($value)
  7030. {
  7031. $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
  7032. }
  7033. public function onCheckDependency($param)
  7034. {
  7035. $this->raiseEvent('OnCheckDependency',$this,$param);
  7036. }
  7037. public function onCalculateKey($param)
  7038. {
  7039. $this->raiseEvent('OnCalculateKey',$this,$param);
  7040. }
  7041. public function render($writer)
  7042. {
  7043. if($this->_dataCached)
  7044. $writer->write($this->_contents);
  7045. else if($this->_cacheAvailable)
  7046. {
  7047. $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
  7048. $stack=$this->getPage()->getCachingStack();
  7049. $stack->push($this);
  7050. parent::render($htmlWriter);
  7051. $stack->pop();
  7052. $content=$htmlWriter->flush();
  7053. $data=array($content,$this->_state,$this->_actions,time());
  7054. $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
  7055. $writer->write($content);
  7056. }
  7057. else
  7058. parent::render($writer);
  7059. }
  7060. }
  7061. class TOutputCacheCheckDependencyEventParameter extends TEventParameter
  7062. {
  7063. private $_isValid=true;
  7064. private $_cacheTime=0;
  7065. public function getIsValid()
  7066. {
  7067. return $this->_isValid;
  7068. }
  7069. public function setIsValid($value)
  7070. {
  7071. $this->_isValid=TPropertyValue::ensureBoolean($value);
  7072. }
  7073. public function getCacheTime()
  7074. {
  7075. return $this->_cacheTime;
  7076. }
  7077. public function setCacheTime($value)
  7078. {
  7079. $this->_cacheTime=TPropertyValue::ensureInteger($value);
  7080. }
  7081. }
  7082. class TOutputCacheCalculateKeyEventParameter extends TEventParameter
  7083. {
  7084. private $_cacheKey='';
  7085. public function getCacheKey()
  7086. {
  7087. return $this->_cacheKey;
  7088. }
  7089. public function setCacheKey($value)
  7090. {
  7091. $this->_cacheKey=TPropertyValue::ensureString($value);
  7092. }
  7093. }
  7094. class TTemplateManager extends TModule
  7095. {
  7096. const TEMPLATE_FILE_EXT='.tpl';
  7097. const TEMPLATE_CACHE_PREFIX='prado:template:';
  7098. public function init($config)
  7099. {
  7100. $this->getService()->setTemplateManager($this);
  7101. }
  7102. public function getTemplateByClassName($className)
  7103. {
  7104. $class=new ReflectionClass($className);
  7105. $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
  7106. return $this->getTemplateByFileName($tplFile);
  7107. }
  7108. public function getTemplateByFileName($fileName)
  7109. {
  7110. if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
  7111. {
  7112. if(($cache=$this->getApplication()->getCache())===null)
  7113. return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
  7114. else
  7115. {
  7116. $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
  7117. if(is_array($array))
  7118. {
  7119. list($template,$timestamps)=$array;
  7120. if($this->getApplication()->getMode()===TApplicationMode::Performance)
  7121. return $template;
  7122. $cacheValid=true;
  7123. foreach($timestamps as $tplFile=>$timestamp)
  7124. {
  7125. if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
  7126. {
  7127. $cacheValid=false;
  7128. break;
  7129. }
  7130. }
  7131. if($cacheValid)
  7132. return $template;
  7133. }
  7134. $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
  7135. $includedFiles=$template->getIncludedFiles();
  7136. $timestamps=array();
  7137. $timestamps[$fileName]=filemtime($fileName);
  7138. foreach($includedFiles as $includedFile)
  7139. $timestamps[$includedFile]=filemtime($includedFile);
  7140. $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
  7141. return $template;
  7142. }
  7143. }
  7144. else
  7145. return null;
  7146. }
  7147. protected function getLocalizedTemplate($filename)
  7148. {
  7149. if(($app=$this->getApplication()->getGlobalization(false))===null)
  7150. return is_file($filename)?$filename:null;
  7151. foreach($app->getLocalizedResource($filename) as $file)
  7152. {
  7153. if(($file=realpath($file))!==false && is_file($file))
  7154. return $file;
  7155. }
  7156. return null;
  7157. }
  7158. }
  7159. class TTemplate extends TApplicationComponent implements ITemplate
  7160. {
  7161. const REGEX_RULES='/<!--.*?--!>|<!---.*?--->|<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|<prop:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/>/msS';
  7162. const CONFIG_DATABIND=0;
  7163. const CONFIG_EXPRESSION=1;
  7164. const CONFIG_ASSET=2;
  7165. const CONFIG_PARAMETER=3;
  7166. const CONFIG_LOCALIZATION=4;
  7167. const CONFIG_TEMPLATE=5;
  7168. private $_tpl=array();
  7169. private $_directive=array();
  7170. private $_contextPath;
  7171. private $_tplFile=null;
  7172. private $_startingLine=0;
  7173. private $_content;
  7174. private $_sourceTemplate=true;
  7175. private $_hashCode='';
  7176. private $_tplControl=null;
  7177. private $_includedFiles=array();
  7178. private $_includeAtLine=array();
  7179. private $_includeLines=array();
  7180. public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
  7181. {
  7182. $this->_sourceTemplate=$sourceTemplate;
  7183. $this->_contextPath=$contextPath;
  7184. $this->_tplFile=$tplFile;
  7185. $this->_startingLine=$startingLine;
  7186. $this->_content=$template;
  7187. $this->_hashCode=md5($template);
  7188. $this->parse($template);
  7189. $this->_content=null;
  7190. }
  7191. public function getTemplateFile()
  7192. {
  7193. return $this->_tplFile;
  7194. }
  7195. public function getIsSourceTemplate()
  7196. {
  7197. return $this->_sourceTemplate;
  7198. }
  7199. public function getContextPath()
  7200. {
  7201. return $this->_contextPath;
  7202. }
  7203. public function getDirective()
  7204. {
  7205. return $this->_directive;
  7206. }
  7207. public function getHashCode()
  7208. {
  7209. return $this->_hashCode;
  7210. }
  7211. public function &getItems()
  7212. {
  7213. return $this->_tpl;
  7214. }
  7215. public function instantiateIn($tplControl,$parentControl=null)
  7216. {
  7217. $this->_tplControl=$tplControl;
  7218. if($parentControl===null)
  7219. $parentControl=$tplControl;
  7220. if(($page=$tplControl->getPage())===null)
  7221. $page=$this->getService()->getRequestedPage();
  7222. $controls=array();
  7223. $directChildren=array();
  7224. foreach($this->_tpl as $key=>$object)
  7225. {
  7226. if($object[0]===-1)
  7227. $parent=$parentControl;
  7228. else if(isset($controls[$object[0]]))
  7229. $parent=$controls[$object[0]];
  7230. else
  7231. continue;
  7232. if(isset($object[2]))
  7233. {
  7234. $component=Prado::createComponent($object[1]);
  7235. $properties=&$object[2];
  7236. if($component instanceof TControl)
  7237. {
  7238. if($component instanceof TOutputCache)
  7239. $component->setCacheKeyPrefix($this->_hashCode.$key);
  7240. $component->setTemplateControl($tplControl);
  7241. if(isset($properties['id']))
  7242. {
  7243. if(is_array($properties['id']))
  7244. $properties['id']=$component->evaluateExpression($properties['id'][1]);
  7245. $tplControl->registerObject($properties['id'],$component);
  7246. }
  7247. if(isset($properties['skinid']))
  7248. {
  7249. if(is_array($properties['skinid']))
  7250. $component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
  7251. else
  7252. $component->setSkinID($properties['skinid']);
  7253. unset($properties['skinid']);
  7254. }
  7255. $component->trackViewState(false);
  7256. $component->applyStyleSheetSkin($page);
  7257. foreach($properties as $name=>$value)
  7258. $this->configureControl($component,$name,$value);
  7259. $component->trackViewState(true);
  7260. if($parent===$parentControl)
  7261. $directChildren[]=$component;
  7262. else
  7263. $component->createdOnTemplate($parent);
  7264. if($component->getAllowChildControls())
  7265. $controls[$key]=$component;
  7266. }
  7267. else if($component instanceof TComponent)
  7268. {
  7269. $controls[$key]=$component;
  7270. if(isset($properties['id']))
  7271. {
  7272. if(is_array($properties['id']))
  7273. $properties['id']=$component->evaluateExpression($properties['id'][1]);
  7274. $tplControl->registerObject($properties['id'],$component);
  7275. if(!$component->hasProperty('id'))
  7276. unset($properties['id']);
  7277. }
  7278. foreach($properties as $name=>$value)
  7279. $this->configureComponent($component,$name,$value);
  7280. if($parent===$parentControl)
  7281. $directChildren[]=$component;
  7282. else
  7283. $component->createdOnTemplate($parent);
  7284. }
  7285. }
  7286. else
  7287. {
  7288. if($object[1] instanceof TCompositeLiteral)
  7289. {
  7290. $o=clone $object[1];
  7291. $o->setContainer($tplControl);
  7292. if($parent===$parentControl)
  7293. $directChildren[]=$o;
  7294. else
  7295. $parent->addParsedObject($o);
  7296. }
  7297. else
  7298. {
  7299. if($parent===$parentControl)
  7300. $directChildren[]=$object[1];
  7301. else
  7302. $parent->addParsedObject($object[1]);
  7303. }
  7304. }
  7305. }
  7306. foreach($directChildren as $control)
  7307. {
  7308. if($control instanceof TComponent)
  7309. $control->createdOnTemplate($parentControl);
  7310. else
  7311. $parentControl->addParsedObject($control);
  7312. }
  7313. }
  7314. protected function configureControl($control,$name,$value)
  7315. {
  7316. if(strncasecmp($name,'on',2)===0)
  7317. $this->configureEvent($control,$name,$value,$control);
  7318. else if(($pos=strrpos($name,'.'))===false)
  7319. $this->configureProperty($control,$name,$value);
  7320. else
  7321. $this->configureSubProperty($control,$name,$value);
  7322. }
  7323. protected function configureComponent($component,$name,$value)
  7324. {
  7325. if(strpos($name,'.')===false)
  7326. $this->configureProperty($component,$name,$value);
  7327. else
  7328. $this->configureSubProperty($component,$name,$value);
  7329. }
  7330. protected function configureEvent($control,$name,$value,$contextControl)
  7331. {
  7332. if(strpos($value,'.')===false)
  7333. $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
  7334. else
  7335. $control->attachEventHandler($name,array($contextControl,$value));
  7336. }
  7337. protected function configureProperty($component,$name,$value)
  7338. {
  7339. if(is_array($value))
  7340. {
  7341. switch($value[0])
  7342. {
  7343. case self::CONFIG_DATABIND:
  7344. $component->bindProperty($name,$value[1]);
  7345. break;
  7346. case self::CONFIG_EXPRESSION:
  7347. if($component instanceof TControl)
  7348. $component->autoBindProperty($name,$value[1]);
  7349. else
  7350. {
  7351. $setter='set'.$name;
  7352. $component->$setter($this->_tplControl->evaluateExpression($value[1]));
  7353. }
  7354. break;
  7355. case self::CONFIG_TEMPLATE:
  7356. $setter='set'.$name;
  7357. $component->$setter($value[1]);
  7358. break;
  7359. case self::CONFIG_ASSET:
  7360. $setter='set'.$name;
  7361. $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
  7362. $component->$setter($url);
  7363. break;
  7364. case self::CONFIG_PARAMETER:
  7365. $setter='set'.$name;
  7366. $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
  7367. break;
  7368. case self::CONFIG_LOCALIZATION:
  7369. $setter='set'.$name;
  7370. $component->$setter(Prado::localize($value[1]));
  7371. break;
  7372. default:
  7373. throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
  7374. break;
  7375. }
  7376. }
  7377. else
  7378. {
  7379. $setter='set'.$name;
  7380. $component->$setter($value);
  7381. }
  7382. }
  7383. protected function configureSubProperty($component,$name,$value)
  7384. {
  7385. if(is_array($value))
  7386. {
  7387. switch($value[0])
  7388. {
  7389. case self::CONFIG_DATABIND:
  7390. $component->bindProperty($name,$value[1]);
  7391. break;
  7392. case self::CONFIG_EXPRESSION:
  7393. if($component instanceof TControl)
  7394. $component->autoBindProperty($name,$value[1]);
  7395. else
  7396. $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
  7397. break;
  7398. case self::CONFIG_TEMPLATE:
  7399. $component->setSubProperty($name,$value[1]);
  7400. break;
  7401. case self::CONFIG_ASSET:
  7402. $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
  7403. $component->setSubProperty($name,$url);
  7404. break;
  7405. case self::CONFIG_PARAMETER:
  7406. $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
  7407. break;
  7408. case self::CONFIG_LOCALIZATION:
  7409. $component->setSubProperty($name,Prado::localize($value[1]));
  7410. break;
  7411. default:
  7412. throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
  7413. break;
  7414. }
  7415. }
  7416. else
  7417. $component->setSubProperty($name,$value);
  7418. }
  7419. protected function parse($input)
  7420. {
  7421. $input=$this->preprocess($input);
  7422. $tpl=&$this->_tpl;
  7423. $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
  7424. $expectPropEnd=false;
  7425. $textStart=0;
  7426. $stack=array();
  7427. $container=-1;
  7428. $matchEnd=0;
  7429. $c=0;
  7430. $this->_directive=null;
  7431. try
  7432. {
  7433. for($i=0;$i<$n;++$i)
  7434. {
  7435. $match=&$matches[$i];
  7436. $str=$match[0][0];
  7437. $matchStart=$match[0][1];
  7438. $matchEnd=$matchStart+strlen($str)-1;
  7439. if(strpos($str,'<com:')===0)
  7440. {
  7441. if($expectPropEnd)
  7442. continue;
  7443. if($matchStart>$textStart)
  7444. $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
  7445. $textStart=$matchEnd+1;
  7446. $type=$match[1][0];
  7447. $attributes=$this->parseAttributes($match[2][0],$match[2][1]);
  7448. $this->validateAttributes($type,$attributes);
  7449. $tpl[$c++]=array($container,$type,$attributes);
  7450. if($str[strlen($str)-2]!=='/')
  7451. {
  7452. $stack[] = $type;
  7453. $container=$c-1;
  7454. }
  7455. }
  7456. else if(strpos($str,'</com:')===0)
  7457. {
  7458. if($expectPropEnd)
  7459. continue;
  7460. if($matchStart>$textStart)
  7461. $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
  7462. $textStart=$matchEnd+1;
  7463. $type=$match[1][0];
  7464. if(empty($stack))
  7465. throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
  7466. $name=array_pop($stack);
  7467. if($name!==$type)
  7468. {
  7469. $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
  7470. throw new TConfigurationException('template_closingtag_expected',$tag);
  7471. }
  7472. $container=$tpl[$container][0];
  7473. }
  7474. else if(strpos($str,'<%@')===0)
  7475. {
  7476. if($expectPropEnd)
  7477. continue;
  7478. if($matchStart>$textStart)
  7479. $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
  7480. $textStart=$matchEnd+1;
  7481. if(isset($tpl[0]) || $this->_directive!==null)
  7482. throw new TConfigurationException('template_directive_nonunique');
  7483. $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
  7484. }
  7485. else if(strpos($str,'<%')===0)
  7486. {
  7487. if($expectPropEnd)
  7488. continue;
  7489. if($matchStart>$textStart)
  7490. $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
  7491. $textStart=$matchEnd+1;
  7492. $literal=trim($match[5][0]);
  7493. if($str[2]==='=')
  7494. $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
  7495. else if($str[2]==='%')
  7496. $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
  7497. else if($str[2]==='#')
  7498. $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
  7499. else if($str[2]==='$')
  7500. $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
  7501. else if($str[2]==='~')
  7502. $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
  7503. else if($str[2]==='/')
  7504. $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'"));
  7505. else if($str[2]==='[')
  7506. {
  7507. $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
  7508. $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
  7509. }
  7510. }
  7511. else if(strpos($str,'<prop:')===0)
  7512. {
  7513. if(strrpos($str,'/>')===strlen($str)-2)
  7514. {
  7515. if($expectPropEnd)
  7516. continue;
  7517. if($matchStart>$textStart)
  7518. $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
  7519. $textStart=$matchEnd+1;
  7520. $prop=strtolower($match[6][0]);
  7521. $attrs=$this->parseAttributes($match[7][0],$match[7][1]);
  7522. $attributes=array();
  7523. foreach($attrs as $name=>$value)
  7524. $attributes[$prop.'.'.$name]=$value;
  7525. $type=$tpl[$container][1];
  7526. $this->validateAttributes($type,$attributes);
  7527. foreach($attributes as $name=>$value)
  7528. {
  7529. if(isset($tpl[$container][2][$name]))
  7530. throw new TConfigurationException('template_property_duplicated',$name);
  7531. $tpl[$container][2][$name]=$value;
  7532. }
  7533. }
  7534. else
  7535. {
  7536. $prop=strtolower($match[3][0]);
  7537. $stack[] = '@'.$prop;
  7538. if(!$expectPropEnd)
  7539. {
  7540. if($matchStart>$textStart)
  7541. $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
  7542. $textStart=$matchEnd+1;
  7543. $expectPropEnd=true;
  7544. }
  7545. }
  7546. }
  7547. else if(strpos($str,'</prop:')===0)
  7548. {
  7549. $prop=strtolower($match[3][0]);
  7550. if(empty($stack))
  7551. throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
  7552. $name=array_pop($stack);
  7553. if($name!=='@'.$prop)
  7554. {
  7555. $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
  7556. throw new TConfigurationException('template_closingtag_expected',$tag);
  7557. }
  7558. if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
  7559. {
  7560. if($matchStart>$textStart)
  7561. {
  7562. $value=substr($input,$textStart,$matchStart-$textStart);
  7563. if(substr($prop,-8,8)==='template')
  7564. $value=$this->parseTemplateProperty($value,$textStart);
  7565. else
  7566. $value=$this->parseAttribute($value);
  7567. if($container>=0)
  7568. {
  7569. $type=$tpl[$container][1];
  7570. $this->validateAttributes($type,array($prop=>$value));
  7571. if(isset($tpl[$container][2][$prop]))
  7572. throw new TConfigurationException('template_property_duplicated',$prop);
  7573. $tpl[$container][2][$prop]=$value;
  7574. }
  7575. else
  7576. $this->_directive[$prop]=$value;
  7577. $textStart=$matchEnd+1;
  7578. }
  7579. $expectPropEnd=false;
  7580. }
  7581. }
  7582. else if(strpos($str,'<!--')===0)
  7583. {
  7584. if($expectPropEnd)
  7585. throw new TConfigurationException('template_comments_forbidden');
  7586. if($matchStart>$textStart)
  7587. $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
  7588. $textStart=$matchEnd+1;
  7589. }
  7590. else
  7591. throw new TConfigurationException('template_matching_unexpected',$match);
  7592. }
  7593. if(!empty($stack))
  7594. {
  7595. $name=array_pop($stack);
  7596. $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
  7597. throw new TConfigurationException('template_closingtag_expected',$tag);
  7598. }
  7599. if($textStart<strlen($input))
  7600. $tpl[$c++]=array($container,substr($input,$textStart));
  7601. }
  7602. catch(Exception $e)
  7603. {
  7604. if(($e instanceof TException) && ($e instanceof TTemplateException))
  7605. throw $e;
  7606. if($matchEnd===0)
  7607. $line=$this->_startingLine+1;
  7608. else
  7609. $line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
  7610. $this->handleException($e,$line,$input);
  7611. }
  7612. if($this->_directive===null)
  7613. $this->_directive=array();
  7614. $objects=array();
  7615. $parent=null;
  7616. $merged=array();
  7617. foreach($tpl as $id=>$object)
  7618. {
  7619. if(isset($object[2]) || $object[0]!==$parent)
  7620. {
  7621. if($parent!==null)
  7622. {
  7623. if(count($merged[1])===1 && is_string($merged[1][0]))
  7624. $objects[$id-1]=array($merged[0],$merged[1][0]);
  7625. else
  7626. $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
  7627. }
  7628. if(isset($object[2]))
  7629. {
  7630. $parent=null;
  7631. $objects[$id]=$object;
  7632. }
  7633. else
  7634. {
  7635. $parent=$object[0];
  7636. $merged=array($parent,array($object[1]));
  7637. }
  7638. }
  7639. else
  7640. $merged[1][]=$object[1];
  7641. }
  7642. if($parent!==null)
  7643. {
  7644. if(count($merged[1])===1 && is_string($merged[1][0]))
  7645. $objects[$id]=array($merged[0],$merged[1][0]);
  7646. else
  7647. $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
  7648. }
  7649. $tpl=$objects;
  7650. return $objects;
  7651. }
  7652. protected function parseAttributes($str,$offset)
  7653. {
  7654. if($str==='')
  7655. return array();
  7656. $pattern='/([\w\.]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
  7657. $attributes=array();
  7658. $n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
  7659. for($i=0;$i<$n;++$i)
  7660. {
  7661. $match=&$matches[$i];
  7662. $name=strtolower($match[1][0]);
  7663. if(isset($attributes[$name]))
  7664. throw new TConfigurationException('template_property_duplicated',$name);
  7665. $value=$match[2][0];
  7666. if(substr($name,-8,8)==='template')
  7667. {
  7668. if($value[0]==='\'' || $value[0]==='"')
  7669. $attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
  7670. else
  7671. $attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
  7672. }
  7673. else
  7674. {
  7675. if($value[0]==='\'' || $value[0]==='"')
  7676. $attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
  7677. else
  7678. $attributes[$name]=$this->parseAttribute($value);
  7679. }
  7680. }
  7681. return $attributes;
  7682. }
  7683. protected function parseTemplateProperty($content,$offset)
  7684. {
  7685. $line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
  7686. return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
  7687. }
  7688. protected function parseAttribute($value)
  7689. {
  7690. if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
  7691. {
  7692. $isDataBind=false;
  7693. $textStart=0;
  7694. $expr='';
  7695. for($i=0;$i<$n;++$i)
  7696. {
  7697. $match=$matches[0][$i];
  7698. $token=$match[0];
  7699. $offset=$match[1];
  7700. $length=strlen($token);
  7701. if($token[2]==='#')
  7702. $isDataBind=true;
  7703. if($offset>$textStart)
  7704. $expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
  7705. $expr.='.('.substr($token,3,$length-5).')';
  7706. $textStart=$offset+$length;
  7707. }
  7708. $length=strlen($value);
  7709. if($length>$textStart)
  7710. $expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
  7711. if($isDataBind)
  7712. return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
  7713. else
  7714. return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
  7715. }
  7716. else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
  7717. {
  7718. $value=$matches[1];
  7719. if($value[2]==='~')
  7720. return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
  7721. elseif($value[2]==='[')
  7722. return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
  7723. elseif($value[2]==='$')
  7724. return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
  7725. elseif($value[2]==='/') {
  7726. $literal = trim(substr($value,3,strlen($value)-5));
  7727. return array(self::CONFIG_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'");
  7728. }
  7729. }
  7730. else
  7731. return $value;
  7732. }
  7733. protected function validateAttributes($type,$attributes)
  7734. {
  7735. Prado::using($type);
  7736. if(($pos=strrpos($type,'.'))!==false)
  7737. $className=substr($type,$pos+1);
  7738. else
  7739. $className=$type;
  7740. $class=new TReflectionClass($className);
  7741. if(is_subclass_of($className,'TControl') || $className==='TControl')
  7742. {
  7743. foreach($attributes as $name=>$att)
  7744. {
  7745. if(($pos=strpos($name,'.'))!==false)
  7746. {
  7747. $subname=substr($name,0,$pos);
  7748. if(!$class->hasMethod('get'.$subname))
  7749. throw new TConfigurationException('template_property_unknown',$type,$subname);
  7750. }
  7751. else if(strncasecmp($name,'on',2)===0)
  7752. {
  7753. if(!$class->hasMethod($name))
  7754. throw new TConfigurationException('template_event_unknown',$type,$name);
  7755. else if(!is_string($att))
  7756. throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
  7757. }
  7758. else
  7759. {
  7760. if(!$class->hasMethod('set'.$name))
  7761. {
  7762. if($class->hasMethod('get'.$name))
  7763. throw new TConfigurationException('template_property_readonly',$type,$name);
  7764. else
  7765. throw new TConfigurationException('template_property_unknown',$type,$name);
  7766. }
  7767. else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
  7768. {
  7769. if(strcasecmp($name,'id')===0)
  7770. throw new TConfigurationException('template_controlid_invalid',$type);
  7771. else if(strcasecmp($name,'skinid')===0)
  7772. throw new TConfigurationException('template_controlskinid_invalid',$type);
  7773. }
  7774. }
  7775. }
  7776. }
  7777. else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
  7778. {
  7779. foreach($attributes as $name=>$att)
  7780. {
  7781. if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
  7782. throw new TConfigurationException('template_databind_forbidden',$type,$name);
  7783. if(($pos=strpos($name,'.'))!==false)
  7784. {
  7785. $subname=substr($name,0,$pos);
  7786. if(!$class->hasMethod('get'.$subname))
  7787. throw new TConfigurationException('template_property_unknown',$type,$subname);
  7788. }
  7789. else if(strncasecmp($name,'on',2)===0)
  7790. throw new TConfigurationException('template_event_forbidden',$type,$name);
  7791. else
  7792. {
  7793. if(strcasecmp($name,'id')!==0 && !$class->hasMethod('set'.$name))
  7794. {
  7795. if($class->hasMethod('get'.$name))
  7796. throw new TConfigurationException('template_property_readonly',$type,$name);
  7797. else
  7798. throw new TConfigurationException('template_property_unknown',$type,$name);
  7799. }
  7800. }
  7801. }
  7802. }
  7803. else
  7804. throw new TConfigurationException('template_component_required',$type);
  7805. }
  7806. public function getIncludedFiles()
  7807. {
  7808. return $this->_includedFiles;
  7809. }
  7810. protected function handleException($e,$line,$input=null)
  7811. {
  7812. $srcFile=$this->_tplFile;
  7813. if(($n=count($this->_includedFiles))>0)
  7814. {
  7815. for($i=$n-1;$i>=0;--$i)
  7816. {
  7817. if($this->_includeAtLine[$i]<=$line)
  7818. {
  7819. if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
  7820. {
  7821. $line=$line-$this->_includeAtLine[$i]+1;
  7822. $srcFile=$this->_includedFiles[$i];
  7823. break;
  7824. }
  7825. else
  7826. $line=$line-$this->_includeLines[$i]+1;
  7827. }
  7828. }
  7829. }
  7830. $exception=new TTemplateException('template_format_invalid',$e->getMessage());
  7831. $exception->setLineNumber($line);
  7832. if(!empty($srcFile))
  7833. $exception->setTemplateFile($srcFile);
  7834. else
  7835. $exception->setTemplateSource($input);
  7836. throw $exception;
  7837. }
  7838. protected function preprocess($input)
  7839. {
  7840. if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
  7841. {
  7842. for($i=0;$i<$n;++$i)
  7843. {
  7844. $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
  7845. if($filePath!==null && is_file($filePath))
  7846. $this->_includedFiles[]=$filePath;
  7847. else
  7848. {
  7849. $errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
  7850. $this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
  7851. }
  7852. }
  7853. $base=0;
  7854. for($i=0;$i<$n;++$i)
  7855. {
  7856. $ext=file_get_contents($this->_includedFiles[$i]);
  7857. $length=strlen($matches[$i][0][0]);
  7858. $offset=$base+$matches[$i][0][1];
  7859. $this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
  7860. $this->_includeLines[$i]=count(explode("\n",$ext));
  7861. $input=substr_replace($input,$ext,$offset,$length);
  7862. $base+=strlen($ext)-$length;
  7863. }
  7864. }
  7865. return $input;
  7866. }
  7867. }
  7868. class TThemeManager extends TModule
  7869. {
  7870. const DEFAULT_BASEPATH='themes';
  7871. private $_initialized=false;
  7872. private $_basePath=null;
  7873. private $_baseUrl=null;
  7874. public function init($config)
  7875. {
  7876. $this->_initialized=true;
  7877. $service=$this->getService();
  7878. if($service instanceof TPageService)
  7879. $service->setThemeManager($this);
  7880. else
  7881. throw new TConfigurationException('thememanager_service_unavailable');
  7882. }
  7883. public function getTheme($name)
  7884. {
  7885. $themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
  7886. $themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
  7887. return new TTheme($themePath,$themeUrl);
  7888. }
  7889. public function getAvailableThemes()
  7890. {
  7891. $themes=array();
  7892. $basePath=$this->getBasePath();
  7893. $folder=@opendir($basePath);
  7894. while($file=@readdir($folder))
  7895. {
  7896. if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
  7897. $themes[]=$file;
  7898. }
  7899. closedir($folder);
  7900. return $themes;
  7901. }
  7902. public function getBasePath()
  7903. {
  7904. if($this->_basePath===null)
  7905. {
  7906. $this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
  7907. if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
  7908. throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
  7909. $this->_basePath=$basePath;
  7910. }
  7911. return $this->_basePath;
  7912. }
  7913. public function setBasePath($value)
  7914. {
  7915. if($this->_initialized)
  7916. throw new TInvalidOperationException('thememanager_basepath_unchangeable');
  7917. else
  7918. {
  7919. $this->_basePath=Prado::getPathOfNamespace($value);
  7920. if($this->_basePath===null || !is_dir($this->_basePath))
  7921. throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
  7922. }
  7923. }
  7924. public function getBaseUrl()
  7925. {
  7926. if($this->_baseUrl===null)
  7927. {
  7928. $appPath=dirname($this->getRequest()->getApplicationFilePath());
  7929. $basePath=$this->getBasePath();
  7930. if(strpos($basePath,$appPath)===false)
  7931. throw new TConfigurationException('thememanager_baseurl_required');
  7932. $appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
  7933. $this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
  7934. }
  7935. return $this->_baseUrl;
  7936. }
  7937. public function setBaseUrl($value)
  7938. {
  7939. $this->_baseUrl=rtrim($value,'/');
  7940. }
  7941. }
  7942. class TTheme extends TApplicationComponent implements ITheme
  7943. {
  7944. const THEME_CACHE_PREFIX='prado:theme:';
  7945. const SKIN_FILE_EXT='.skin';
  7946. private $_themePath;
  7947. private $_themeUrl;
  7948. private $_skins=null;
  7949. private $_name='';
  7950. private $_cssFiles=array();
  7951. private $_jsFiles=array();
  7952. public function __construct($themePath,$themeUrl)
  7953. {
  7954. $this->_themeUrl=$themeUrl;
  7955. $this->_themePath=realpath($themePath);
  7956. $this->_name=basename($themePath);
  7957. $cacheValid=false;
  7958. if(($cache=$this->getApplication()->getCache())!==null)
  7959. {
  7960. $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
  7961. if(is_array($array))
  7962. {
  7963. list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
  7964. if($this->getApplication()->getMode()!==TApplicationMode::Performance)
  7965. {
  7966. if(($dir=opendir($themePath))===false)
  7967. throw new TIOException('theme_path_inexistent',$themePath);
  7968. $cacheValid=true;
  7969. while(($file=readdir($dir))!==false)
  7970. {
  7971. if($file==='.' || $file==='..')
  7972. continue;
  7973. else if(basename($file,'.css')!==$file)
  7974. $this->_cssFiles[]=$themeUrl.'/'.$file;
  7975. else if(basename($file,'.js')!==$file)
  7976. $this->_jsFiles[]=$themeUrl.'/'.$file;
  7977. else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
  7978. {
  7979. $cacheValid=false;
  7980. break;
  7981. }
  7982. }
  7983. closedir($dir);
  7984. if($cacheValid)
  7985. $this->_skins=$skins;
  7986. }
  7987. else
  7988. {
  7989. $cacheValid=true;
  7990. $this->_cssFiles=$cssFiles;
  7991. $this->_jsFiles=$jsFiles;
  7992. $this->_skins=$skins;
  7993. }
  7994. }
  7995. }
  7996. if(!$cacheValid)
  7997. {
  7998. $this->_cssFiles=array();
  7999. $this->_jsFiles=array();
  8000. $this->_skins=array();
  8001. if(($dir=opendir($themePath))===false)
  8002. throw new TIOException('theme_path_inexistent',$themePath);
  8003. while(($file=readdir($dir))!==false)
  8004. {
  8005. if($file==='.' || $file==='..')
  8006. continue;
  8007. else if(basename($file,'.css')!==$file)
  8008. $this->_cssFiles[]=$themeUrl.'/'.$file;
  8009. else if(basename($file,'.js')!==$file)
  8010. $this->_jsFiles[]=$themeUrl.'/'.$file;
  8011. else if(basename($file,self::SKIN_FILE_EXT)!==$file)
  8012. {
  8013. $template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
  8014. foreach($template->getItems() as $skin)
  8015. {
  8016. if(!isset($skin[2]))
  8017. continue;
  8018. else if($skin[0]!==-1)
  8019. throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
  8020. $type=$skin[1];
  8021. $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
  8022. unset($skin[2]['skinid']);
  8023. if(isset($this->_skins[$type][$id]))
  8024. throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
  8025. $this->_skins[$type][$id]=$skin[2];
  8026. }
  8027. }
  8028. }
  8029. closedir($dir);
  8030. sort($this->_cssFiles);
  8031. sort($this->_jsFiles);
  8032. if($cache!==null)
  8033. $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
  8034. }
  8035. }
  8036. public function getName()
  8037. {
  8038. return $this->_name;
  8039. }
  8040. protected function setName($value)
  8041. {
  8042. $this->_name = $value;
  8043. }
  8044. public function getBaseUrl()
  8045. {
  8046. return $this->_themeUrl;
  8047. }
  8048. protected function setBaseUrl($value)
  8049. {
  8050. $this->_themeUrl=rtrim($value,'/');
  8051. }
  8052. public function getBasePath()
  8053. {
  8054. return $this->_themePath;
  8055. }
  8056. protected function setBasePath($value)
  8057. {
  8058. $this->_themePath=$value;
  8059. }
  8060. public function getSkins()
  8061. {
  8062. return $this->_skins;
  8063. }
  8064. protected function setSkins($value)
  8065. {
  8066. $this->_skins = $value;
  8067. }
  8068. public function applySkin($control)
  8069. {
  8070. $type=get_class($control);
  8071. if(($id=$control->getSkinID())==='')
  8072. $id=0;
  8073. if(isset($this->_skins[$type][$id]))
  8074. {
  8075. foreach($this->_skins[$type][$id] as $name=>$value)
  8076. {
  8077. if(is_array($value))
  8078. {
  8079. switch($value[0])
  8080. {
  8081. case TTemplate::CONFIG_EXPRESSION:
  8082. $value=$this->evaluateExpression($value[1]);
  8083. break;
  8084. case TTemplate::CONFIG_ASSET:
  8085. $value=$this->_themeUrl.'/'.ltrim($value[1],'/');
  8086. break;
  8087. case TTemplate::CONFIG_DATABIND:
  8088. $control->bindProperty($name,$value[1]);
  8089. break;
  8090. case TTemplate::CONFIG_PARAMETER:
  8091. $control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
  8092. break;
  8093. case TTemplate::CONFIG_TEMPLATE:
  8094. $control->setSubProperty($name,$value[1]);
  8095. break;
  8096. case TTemplate::CONFIG_LOCALIZATION:
  8097. $control->setSubProperty($name,Prado::localize($value[1]));
  8098. break;
  8099. default:
  8100. throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
  8101. break;
  8102. }
  8103. }
  8104. if(!is_array($value))
  8105. {
  8106. if(strpos($name,'.')===false)
  8107. {
  8108. if($control->hasProperty($name))
  8109. {
  8110. if($control->canSetProperty($name))
  8111. {
  8112. $setter='set'.$name;
  8113. $control->$setter($value);
  8114. }
  8115. else
  8116. throw new TConfigurationException('theme_property_readonly',$type,$name);
  8117. }
  8118. else
  8119. throw new TConfigurationException('theme_property_undefined',$type,$name);
  8120. }
  8121. else
  8122. $control->setSubProperty($name,$value);
  8123. }
  8124. }
  8125. return true;
  8126. }
  8127. else
  8128. return false;
  8129. }
  8130. public function getStyleSheetFiles()
  8131. {
  8132. return $this->_cssFiles;
  8133. }
  8134. protected function setStyleSheetFiles($value)
  8135. {
  8136. $this->_cssFiles=$value;
  8137. }
  8138. public function getJavaScriptFiles()
  8139. {
  8140. return $this->_jsFiles;
  8141. }
  8142. protected function setJavaScriptFiles($value)
  8143. {
  8144. $this->_jsFiles=$value;
  8145. }
  8146. }
  8147. class TPageService extends TService
  8148. {
  8149. const CONFIG_FILE='config.xml';
  8150. const DEFAULT_BASEPATH='pages';
  8151. const CONFIG_CACHE_PREFIX='prado:pageservice:';
  8152. const PAGE_FILE_EXT='.page';
  8153. private $_basePath=null;
  8154. private $_basePageClass='TPage';
  8155. private $_clientScriptManagerClass='System.Web.UI.TClientScriptManager';
  8156. private $_defaultPage='Home';
  8157. private $_pagePath=null;
  8158. private $_page=null;
  8159. private $_properties=array();
  8160. private $_initialized=false;
  8161. private $_themeManager=null;
  8162. private $_templateManager=null;
  8163. public function init($config)
  8164. {
  8165. $pageConfig=$this->loadPageConfig($config);
  8166. $this->initPageContext($pageConfig);
  8167. $this->_initialized=true;
  8168. }
  8169. protected function initPageContext($pageConfig)
  8170. {
  8171. $application=$this->getApplication();
  8172. foreach($pageConfig->getApplicationConfigurations() as $appConfig)
  8173. $application->applyConfiguration($appConfig);
  8174. $this->applyConfiguration($pageConfig);
  8175. }
  8176. protected function applyConfiguration($config)
  8177. {
  8178. $this->_properties=array_merge($this->_properties, $config->getProperties());
  8179. $this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
  8180. $pagePath=$this->getRequestedPagePath();
  8181. foreach($config->getExternalConfigurations() as $filePath=>$params)
  8182. {
  8183. list($configPagePath,$condition)=$params;
  8184. if($condition!==true)
  8185. $condition=$this->evaluateExpression($condition);
  8186. if($condition)
  8187. {
  8188. if(($path=Prado::getPathOfNamespace($filePath,TApplication::CONFIG_FILE_EXT))===null || !is_file($path))
  8189. throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
  8190. $c=new TPageConfiguration($pagePath);
  8191. $c->loadFromFile($path,$configPagePath);
  8192. $this->applyConfiguration($c);
  8193. }
  8194. }
  8195. }
  8196. protected function determineRequestedPagePath()
  8197. {
  8198. $pagePath=$this->getRequest()->getServiceParameter();
  8199. if(empty($pagePath))
  8200. $pagePath=$this->getDefaultPage();
  8201. return $pagePath;
  8202. }
  8203. protected function loadPageConfig($config)
  8204. {
  8205. $application=$this->getApplication();
  8206. $pagePath=$this->getRequestedPagePath();
  8207. if(($cache=$application->getCache())===null)
  8208. {
  8209. $pageConfig=new TPageConfiguration($pagePath);
  8210. if($config!==null)
  8211. $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
  8212. $pageConfig->loadFromFiles($this->getBasePath());
  8213. }
  8214. else
  8215. {
  8216. $configCached=true;
  8217. $currentTimestamp=array();
  8218. $arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
  8219. if(is_array($arr))
  8220. {
  8221. list($pageConfig,$timestamps)=$arr;
  8222. if($application->getMode()!==TApplicationMode::Performance)
  8223. {
  8224. foreach($timestamps as $fileName=>$timestamp)
  8225. {
  8226. if($fileName===0)
  8227. {
  8228. $appConfigFile=$application->getConfigurationFile();
  8229. $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
  8230. if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
  8231. $configCached=false;
  8232. }
  8233. else
  8234. {
  8235. $currentTimestamp[$fileName]=@filemtime($fileName);
  8236. if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
  8237. $configCached=false;
  8238. }
  8239. }
  8240. }
  8241. }
  8242. else
  8243. {
  8244. $configCached=false;
  8245. $paths=explode('.',$pagePath);
  8246. $configPath=$this->getBasePath();
  8247. foreach($paths as $path)
  8248. {
  8249. $configFile=$configPath.DIRECTORY_SEPARATOR.self::CONFIG_FILE;
  8250. $currentTimestamp[$configFile]=@filemtime($configFile);
  8251. $configPath.=DIRECTORY_SEPARATOR.$path;
  8252. }
  8253. $appConfigFile=$application->getConfigurationFile();
  8254. $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
  8255. }
  8256. if(!$configCached)
  8257. {
  8258. $pageConfig=new TPageConfiguration($pagePath);
  8259. if($config!==null)
  8260. $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
  8261. $pageConfig->loadFromFiles($this->getBasePath());
  8262. $cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
  8263. }
  8264. }
  8265. return $pageConfig;
  8266. }
  8267. public function getTemplateManager()
  8268. {
  8269. if(!$this->_templateManager)
  8270. {
  8271. $this->_templateManager=new TTemplateManager;
  8272. $this->_templateManager->init(null);
  8273. }
  8274. return $this->_templateManager;
  8275. }
  8276. public function setTemplateManager(TTemplateManager $value)
  8277. {
  8278. $this->_templateManager=$value;
  8279. }
  8280. public function getThemeManager()
  8281. {
  8282. if(!$this->_themeManager)
  8283. {
  8284. $this->_themeManager=new TThemeManager;
  8285. $this->_themeManager->init(null);
  8286. }
  8287. return $this->_themeManager;
  8288. }
  8289. public function setThemeManager(TThemeManager $value)
  8290. {
  8291. $this->_themeManager=$value;
  8292. }
  8293. public function getRequestedPagePath()
  8294. {
  8295. if($this->_pagePath===null)
  8296. {
  8297. $this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
  8298. if(empty($this->_pagePath))
  8299. throw new THttpException(404,'pageservice_page_required');
  8300. }
  8301. return $this->_pagePath;
  8302. }
  8303. public function getRequestedPage()
  8304. {
  8305. return $this->_page;
  8306. }
  8307. public function getDefaultPage()
  8308. {
  8309. return $this->_defaultPage;
  8310. }
  8311. public function setDefaultPage($value)
  8312. {
  8313. if($this->_initialized)
  8314. throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
  8315. else
  8316. $this->_defaultPage=$value;
  8317. }
  8318. public function getDefaultPageUrl()
  8319. {
  8320. return $this->constructUrl($this->getDefaultPage());
  8321. }
  8322. public function getBasePath()
  8323. {
  8324. if($this->_basePath===null)
  8325. {
  8326. $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
  8327. if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
  8328. throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
  8329. }
  8330. return $this->_basePath;
  8331. }
  8332. public function setBasePath($value)
  8333. {
  8334. if($this->_initialized)
  8335. throw new TInvalidOperationException('pageservice_basepath_unchangeable');
  8336. else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
  8337. throw new TConfigurationException('pageservice_basepath_invalid',$value);
  8338. $this->_basePath=realpath($path);
  8339. }
  8340. public function setBasePageClass($value)
  8341. {
  8342. $this->_basePageClass=$value;
  8343. }
  8344. public function getBasePageClass()
  8345. {
  8346. return $this->_basePageClass;
  8347. }
  8348. public function setClientScriptManagerClass($value)
  8349. {
  8350. $this->_clientScriptManagerClass=$value;
  8351. }
  8352. public function getClientScriptManagerClass()
  8353. {
  8354. return $this->_clientScriptManagerClass;
  8355. }
  8356. public function run()
  8357. {
  8358. $this->_page=$this->createPage($this->getRequestedPagePath());
  8359. $this->runPage($this->_page,$this->_properties);
  8360. }
  8361. protected function createPage($pagePath)
  8362. {
  8363. $path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
  8364. $hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
  8365. $hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
  8366. if(!$hasTemplateFile && !$hasClassFile)
  8367. throw new THttpException(404,'pageservice_page_unknown',$pagePath);
  8368. if($hasClassFile)
  8369. {
  8370. $className=basename($path);
  8371. if(!class_exists($className,false))
  8372. include_once($path.Prado::CLASS_FILE_EXT);
  8373. }
  8374. else
  8375. {
  8376. $className=$this->getBasePageClass();
  8377. Prado::using($className);
  8378. if(($pos=strrpos($className,'.'))!==false)
  8379. $className=substr($className,$pos+1);
  8380. }
  8381. if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
  8382. throw new THttpException(404,'pageservice_page_unknown',$pagePath);
  8383. $page=new $className;
  8384. $page->setPagePath($pagePath);
  8385. if($hasTemplateFile)
  8386. $page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
  8387. return $page;
  8388. }
  8389. protected function runPage($page,$properties)
  8390. {
  8391. foreach($properties as $name=>$value)
  8392. $page->setSubProperty($name,$value);
  8393. $page->run($this->getResponse()->createHtmlWriter());
  8394. }
  8395. public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
  8396. {
  8397. return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
  8398. }
  8399. }
  8400. class TPageConfiguration extends TComponent
  8401. {
  8402. private $_appConfigs=array();
  8403. private $_properties=array();
  8404. private $_rules=array();
  8405. private $_includes=array();
  8406. private $_pagePath='';
  8407. public function __construct($pagePath)
  8408. {
  8409. $this->_pagePath=$pagePath;
  8410. }
  8411. public function getExternalConfigurations()
  8412. {
  8413. return $this->_includes;
  8414. }
  8415. public function getProperties()
  8416. {
  8417. return $this->_properties;
  8418. }
  8419. public function getRules()
  8420. {
  8421. return $this->_rules;
  8422. }
  8423. public function getApplicationConfigurations()
  8424. {
  8425. return $this->_appConfigs;
  8426. }
  8427. public function loadFromFiles($basePath)
  8428. {
  8429. $paths=explode('.',$this->_pagePath);
  8430. $page=array_pop($paths);
  8431. $path=$basePath;
  8432. $configPagePath='';
  8433. foreach($paths as $p)
  8434. {
  8435. $this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath);
  8436. $path.=DIRECTORY_SEPARATOR.$p;
  8437. if($configPagePath==='')
  8438. $configPagePath=$p;
  8439. else
  8440. $configPagePath.='.'.$p;
  8441. }
  8442. $this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath);
  8443. $this->_rules=new TAuthorizationRuleCollection($this->_rules);
  8444. }
  8445. public function loadFromFile($fname,$configPagePath)
  8446. {
  8447. if(empty($fname) || !is_file($fname))
  8448. return;
  8449. $dom=new TXmlDocument;
  8450. if($dom->loadFromFile($fname))
  8451. $this->loadFromXml($dom,dirname($fname),$configPagePath);
  8452. else
  8453. throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
  8454. }
  8455. public function loadFromXml($dom,$configPath,$configPagePath)
  8456. {
  8457. $this->loadApplicationConfigurationFromXml($dom,$configPath);
  8458. $this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
  8459. }
  8460. public function loadApplicationConfigurationFromXml($dom,$configPath)
  8461. {
  8462. $appConfig=new TApplicationConfiguration;
  8463. $appConfig->loadFromXml($dom,$configPath);
  8464. $this->_appConfigs[]=$appConfig;
  8465. }
  8466. public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
  8467. {
  8468. if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
  8469. {
  8470. $rules=array();
  8471. foreach($authorizationNode->getElements() as $node)
  8472. {
  8473. $patterns=$node->getAttribute('pages');
  8474. $ruleApplies=false;
  8475. if(empty($patterns) || trim($patterns)==='*')
  8476. $ruleApplies=true;
  8477. else
  8478. {
  8479. foreach(explode(',',$patterns) as $pattern)
  8480. {
  8481. if(($pattern=trim($pattern))!=='')
  8482. {
  8483. if($configPagePath!=='')
  8484. $pattern=$configPagePath.'.'.$pattern;
  8485. if(strcasecmp($pattern,$this->_pagePath)===0)
  8486. {
  8487. $ruleApplies=true;
  8488. break;
  8489. }
  8490. if($pattern[strlen($pattern)-1]==='*')
  8491. {
  8492. if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
  8493. {
  8494. $ruleApplies=true;
  8495. break;
  8496. }
  8497. }
  8498. }
  8499. }
  8500. }
  8501. if($ruleApplies)
  8502. $rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
  8503. }
  8504. $this->_rules=array_merge($rules,$this->_rules);
  8505. }
  8506. if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
  8507. {
  8508. $this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
  8509. foreach($pagesNode->getElementsByTagName('page') as $node)
  8510. {
  8511. $properties=$node->getAttributes();
  8512. $id=$properties->remove('id');
  8513. if(empty($id))
  8514. throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
  8515. $matching=false;
  8516. $id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
  8517. if(strcasecmp($id,$this->_pagePath)===0)
  8518. $matching=true;
  8519. else if($id[strlen($id)-1]==='*')
  8520. $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
  8521. if($matching)
  8522. $this->_properties=array_merge($this->_properties,$properties->toArray());
  8523. }
  8524. }
  8525. foreach($dom->getElementsByTagName('include') as $node)
  8526. {
  8527. if(($when=$node->getAttribute('when'))===null)
  8528. $when=true;
  8529. if(($filePath=$node->getAttribute('file'))===null)
  8530. throw new TConfigurationException('pageserviceconf_includefile_required');
  8531. if(isset($this->_includes[$filePath]))
  8532. $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
  8533. else
  8534. $this->_includes[$filePath]=array($configPagePath,$when);
  8535. }
  8536. }
  8537. }
  8538. class TAssetManager extends TModule
  8539. {
  8540. const DEFAULT_BASEPATH='assets';
  8541. private $_basePath=null;
  8542. private $_baseUrl=null;
  8543. private $_checkTimestamp=false;
  8544. private $_application;
  8545. private $_published=array();
  8546. private $_initialized=false;
  8547. public function init($config)
  8548. {
  8549. $application=$this->getApplication();
  8550. if($this->_basePath===null)
  8551. $this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
  8552. if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
  8553. throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
  8554. if($this->_baseUrl===null)
  8555. $this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
  8556. $application->setAssetManager($this);
  8557. $this->_initialized=true;
  8558. }
  8559. public function getBasePath()
  8560. {
  8561. return $this->_basePath;
  8562. }
  8563. public function setBasePath($value)
  8564. {
  8565. if($this->_initialized)
  8566. throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
  8567. else
  8568. {
  8569. $this->_basePath=Prado::getPathOfNamespace($value);
  8570. if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
  8571. throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value);
  8572. }
  8573. }
  8574. public function getBaseUrl()
  8575. {
  8576. return $this->_baseUrl;
  8577. }
  8578. public function setBaseUrl($value)
  8579. {
  8580. if($this->_initialized)
  8581. throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
  8582. else
  8583. $this->_baseUrl=rtrim($value,'/');
  8584. }
  8585. public function publishFilePath($path,$checkTimestamp=false)
  8586. {
  8587. if(isset($this->_published[$path]))
  8588. return $this->_published[$path];
  8589. else if(empty($path) || ($fullpath=realpath($path))===false)
  8590. throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
  8591. else if(is_file($fullpath))
  8592. {
  8593. $dir=$this->hash(dirname($fullpath));
  8594. $fileName=basename($fullpath);
  8595. $dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
  8596. if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
  8597. $this->copyFile($fullpath,$dst);
  8598. return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
  8599. }
  8600. else
  8601. {
  8602. $dir=$this->hash($fullpath);
  8603. if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
  8604. {
  8605. $this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
  8606. }
  8607. return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
  8608. }
  8609. }
  8610. protected function getPublished()
  8611. {
  8612. return $this->_published;
  8613. }
  8614. protected function setPublished($values=array())
  8615. {
  8616. $this->_published = $values;
  8617. }
  8618. public function getPublishedPath($path)
  8619. {
  8620. $path=realpath($path);
  8621. if(is_file($path))
  8622. return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
  8623. else
  8624. return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
  8625. }
  8626. public function getPublishedUrl($path)
  8627. {
  8628. $path=realpath($path);
  8629. if(is_file($path))
  8630. return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
  8631. else
  8632. return $this->_baseUrl.'/'.$this->hash($path);
  8633. }
  8634. protected function hash($dir)
  8635. {
  8636. return sprintf('%x',crc32($dir.Prado::getVersion()));
  8637. }
  8638. protected function copyFile($src,$dst)
  8639. {
  8640. if(!is_dir($dst))
  8641. {
  8642. @mkdir($dst);
  8643. @chmod($dst, PRADO_CHMOD);
  8644. }
  8645. $dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
  8646. if(@filemtime($dstFile)<@filemtime($src))
  8647. {
  8648. @copy($src,$dstFile);
  8649. }
  8650. }
  8651. public function copyDirectory($src,$dst)
  8652. {
  8653. if(!is_dir($dst))
  8654. {
  8655. @mkdir($dst);
  8656. @chmod($dst, PRADO_CHMOD);
  8657. }
  8658. if($folder=@opendir($src))
  8659. {
  8660. while($file=@readdir($folder))
  8661. {
  8662. if($file==='.' || $file==='..' || $file==='.svn')
  8663. continue;
  8664. else if(is_file($src.DIRECTORY_SEPARATOR.$file))
  8665. {
  8666. if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
  8667. {
  8668. @copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
  8669. @chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
  8670. }
  8671. }
  8672. else
  8673. $this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
  8674. }
  8675. closedir($folder);
  8676. } else {
  8677. throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
  8678. }
  8679. }
  8680. public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
  8681. {
  8682. if(isset($this->_published[$md5sum]))
  8683. return $this->_published[$md5sum];
  8684. else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
  8685. throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
  8686. else
  8687. {
  8688. $dir=$this->hash(dirname($fullpath));
  8689. $fileName=basename($fullpath);
  8690. $dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
  8691. if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
  8692. {
  8693. if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
  8694. {
  8695. $this->copyFile($fullpath,$dst);
  8696. $this->deployTarFile($tarfile,$dst);
  8697. }
  8698. }
  8699. return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
  8700. }
  8701. }
  8702. protected function deployTarFile($path,$destination)
  8703. {
  8704. if(($fullpath=realpath($path))===false || !is_file($fullpath))
  8705. throw new TIOException('assetmanager_tarfile_invalid',$path);
  8706. else
  8707. {
  8708. Prado::using('System.IO.TTarFileExtractor');
  8709. $tar = new TTarFileExtractor($fullpath);
  8710. return $tar->extract($destination);
  8711. }
  8712. }
  8713. }
  8714. class TGlobalization extends TModule
  8715. {
  8716. private $_defaultCharset = 'UTF-8';
  8717. private $_defaultCulture = 'en';
  8718. private $_charset=null;
  8719. private $_culture=null;
  8720. private $_translation;
  8721. private $_translateDefaultCulture=true;
  8722. public function init($xml)
  8723. {
  8724. if($this->_charset===null)
  8725. $this->_charset=$this->getDefaultCharset();
  8726. if($this->_culture===null)
  8727. $this->_culture=$this->getDefaultCulture();
  8728. if($xml!==null)
  8729. {
  8730. $translation = $xml->getElementByTagName('translation');
  8731. if($translation)
  8732. $this->setTranslationConfiguration($translation->getAttributes());
  8733. }
  8734. $this->getApplication()->setGlobalization($this);
  8735. }
  8736. public function getTranslateDefaultCulture()
  8737. {
  8738. return $this->_translateDefaultCulture;
  8739. }
  8740. public function setTranslateDefaultCulture($value)
  8741. {
  8742. $this->_translateDefaultCulture = TPropertyValue::ensureBoolean($value);
  8743. }
  8744. public function getDefaultCulture()
  8745. {
  8746. return $this->_defaultCulture;
  8747. }
  8748. public function setDefaultCulture($culture)
  8749. {
  8750. $this->_defaultCulture = str_replace('-','_',$culture);
  8751. }
  8752. public function getDefaultCharset()
  8753. {
  8754. return $this->_defaultCharset;
  8755. }
  8756. public function setDefaultCharset($charset)
  8757. {
  8758. $this->_defaultCharset = $charset;
  8759. }
  8760. public function getCulture()
  8761. {
  8762. return $this->_culture;
  8763. }
  8764. public function setCulture($culture)
  8765. {
  8766. $this->_culture = str_replace('-','_',$culture);
  8767. }
  8768. public function getCharset()
  8769. {
  8770. return $this->_charset;
  8771. }
  8772. public function setCharset($charset)
  8773. {
  8774. $this->_charset = $charset;
  8775. }
  8776. public function getTranslationConfiguration()
  8777. {
  8778. return (!$this->_translateDefaultCulture && ($this->getDefaultCulture() == $this->getCulture()))
  8779. ? null
  8780. : $this->_translation;
  8781. }
  8782. protected function setTranslationConfiguration(TMap $config)
  8783. {
  8784. if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
  8785. {
  8786. if($config['source'])
  8787. {
  8788. $config['source'] = Prado::getPathOfNamespace($config['source']);
  8789. if(!is_dir($config['source']))
  8790. {
  8791. if(@mkdir($config['source'])===false)
  8792. throw new TConfigurationException('globalization_source_path_failed',
  8793. $config['source']);
  8794. chmod($config['source'], PRADO_CHMOD);
  8795. }
  8796. }
  8797. else
  8798. {
  8799. throw new TConfigurationException("invalid source dir '{$config['source']}'");
  8800. }
  8801. }
  8802. if($config['cache'])
  8803. {
  8804. $config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
  8805. if(!is_dir($config['cache']))
  8806. {
  8807. if(@mkdir($config['cache'])===false)
  8808. throw new TConfigurationException('globalization_cache_path_failed',
  8809. $config['cache']);
  8810. chmod($config['cache'], PRADO_CHMOD);
  8811. }
  8812. }
  8813. $this->_translation = $config;
  8814. }
  8815. public function getTranslationCatalogue()
  8816. {
  8817. return $this->_translation['catalogue'];
  8818. }
  8819. public function setTranslationCatalogue($value)
  8820. {
  8821. $this->_translation['catalogue'] = $value;
  8822. }
  8823. public function getCultureVariants($culture=null)
  8824. {
  8825. if($culture===null) $culture = $this->getCulture();
  8826. $variants = explode('_', $culture);
  8827. $result = array();
  8828. for(; count($variants) > 0; array_pop($variants))
  8829. $result[] = implode('_', $variants);
  8830. return $result;
  8831. }
  8832. public function getLocalizedResource($file,$culture=null)
  8833. {
  8834. $files = array();
  8835. $variants = $this->getCultureVariants($culture);
  8836. $path = pathinfo($file);
  8837. foreach($variants as $variant)
  8838. $files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename'];
  8839. $filename = substr($path['basename'],0,strrpos($path['basename'],'.'));
  8840. foreach($variants as $variant)
  8841. $files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension'];
  8842. $files[] = $file;
  8843. return $files;
  8844. }
  8845. }
  8846. class TApplication extends TComponent
  8847. {
  8848. const STATE_OFF='Off';
  8849. const STATE_DEBUG='Debug';
  8850. const STATE_NORMAL='Normal';
  8851. const STATE_PERFORMANCE='Performance';
  8852. const PAGE_SERVICE_ID='page';
  8853. const CONFIG_FILE='application.xml';
  8854. const CONFIG_FILE_EXT='.xml';
  8855. const RUNTIME_PATH='runtime';
  8856. const CONFIGCACHE_FILE='config.cache';
  8857. const GLOBAL_FILE='global.cache';
  8858. private static $_steps=array(
  8859. 'onBeginRequest',
  8860. 'onLoadState',
  8861. 'onLoadStateComplete',
  8862. 'onAuthentication',
  8863. 'onAuthenticationComplete',
  8864. 'onAuthorization',
  8865. 'onAuthorizationComplete',
  8866. 'onPreRunService',
  8867. 'runService',
  8868. 'onSaveState',
  8869. 'onSaveStateComplete',
  8870. 'onPreFlushOutput',
  8871. 'flushOutput'
  8872. );
  8873. private $_id;
  8874. private $_uniqueID;
  8875. private $_requestCompleted=false;
  8876. private $_step;
  8877. private $_services;
  8878. private $_service;
  8879. private $_modules=array();
  8880. private $_parameters;
  8881. private $_configFile;
  8882. private $_basePath;
  8883. private $_runtimePath;
  8884. private $_stateChanged=false;
  8885. private $_globals=array();
  8886. private $_cacheFile;
  8887. private $_errorHandler;
  8888. private $_request;
  8889. private $_response;
  8890. private $_session;
  8891. private $_cache;
  8892. private $_statePersister;
  8893. private $_user;
  8894. private $_globalization;
  8895. private $_security;
  8896. private $_assetManager;
  8897. private $_authRules;
  8898. private $_mode=TApplicationMode::Debug;
  8899. private $_pageServiceID = self::PAGE_SERVICE_ID;
  8900. public function __construct($basePath='protected',$cacheConfig=true)
  8901. {
  8902. Prado::setApplication($this);
  8903. $this->resolvePaths($basePath);
  8904. if($cacheConfig)
  8905. $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
  8906. $this->_uniqueID=md5($this->_runtimePath);
  8907. $this->_parameters=new TMap;
  8908. $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
  8909. Prado::setPathOfAlias('Application',$this->_basePath);
  8910. }
  8911. protected function resolvePaths($basePath)
  8912. {
  8913. if(empty($basePath) || ($basePath=realpath($basePath))===false)
  8914. throw new TConfigurationException('application_basepath_invalid',$basePath);
  8915. if(is_file($basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE))
  8916. $configFile=$basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE;
  8917. else if(is_file($basePath))
  8918. {
  8919. $configFile=$basePath;
  8920. $basePath=dirname($configFile);
  8921. }
  8922. else
  8923. $configFile=null;
  8924. $runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
  8925. if(is_writable($runtimePath))
  8926. {
  8927. if($configFile!==null)
  8928. {
  8929. $runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
  8930. if(!is_dir($runtimePath))
  8931. {
  8932. if(@mkdir($runtimePath)===false)
  8933. throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
  8934. @chmod($runtimePath, PRADO_CHMOD); }
  8935. $this->setConfigurationFile($configFile);
  8936. }
  8937. $this->setBasePath($basePath);
  8938. $this->setRuntimePath($runtimePath);
  8939. }
  8940. else
  8941. throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
  8942. }
  8943. public function run()
  8944. {
  8945. try
  8946. {
  8947. $this->initApplication();
  8948. $n=count(self::$_steps);
  8949. $this->_step=0;
  8950. $this->_requestCompleted=false;
  8951. while($this->_step<$n)
  8952. {
  8953. if($this->_mode===self::STATE_OFF)
  8954. throw new THttpException(503,'application_unavailable');
  8955. if($this->_requestCompleted)
  8956. break;
  8957. $method=self::$_steps[$this->_step];
  8958. $this->$method();
  8959. $this->_step++;
  8960. }
  8961. }
  8962. catch(Exception $e)
  8963. {
  8964. $this->onError($e);
  8965. }
  8966. $this->onEndRequest();
  8967. }
  8968. public function completeRequest()
  8969. {
  8970. $this->_requestCompleted=true;
  8971. }
  8972. public function getRequestCompleted()
  8973. {
  8974. return $this->_requestCompleted;
  8975. }
  8976. public function getGlobalState($key,$defaultValue=null)
  8977. {
  8978. return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
  8979. }
  8980. public function setGlobalState($key,$value,$defaultValue=null)
  8981. {
  8982. $this->_stateChanged=true;
  8983. if($value===$defaultValue)
  8984. unset($this->_globals[$key]);
  8985. else
  8986. $this->_globals[$key]=$value;
  8987. }
  8988. public function clearGlobalState($key)
  8989. {
  8990. $this->_stateChanged=true;
  8991. unset($this->_globals[$key]);
  8992. }
  8993. protected function loadGlobals()
  8994. {
  8995. $this->_globals=$this->getApplicationStatePersister()->load();
  8996. }
  8997. protected function saveGlobals()
  8998. {
  8999. if($this->_stateChanged)
  9000. {
  9001. $this->_stateChanged=false;
  9002. $this->getApplicationStatePersister()->save($this->_globals);
  9003. }
  9004. }
  9005. public function getID()
  9006. {
  9007. return $this->_id;
  9008. }
  9009. public function setID($value)
  9010. {
  9011. $this->_id=$value;
  9012. }
  9013. public function getPageServiceID()
  9014. {
  9015. return $this->_pageServiceID;
  9016. }
  9017. public function setPageServiceID($value)
  9018. {
  9019. $this->_pageServiceID=$value;
  9020. }
  9021. public function getUniqueID()
  9022. {
  9023. return $this->_uniqueID;
  9024. }
  9025. public function getMode()
  9026. {
  9027. return $this->_mode;
  9028. }
  9029. public function setMode($value)
  9030. {
  9031. $this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
  9032. }
  9033. public function getBasePath()
  9034. {
  9035. return $this->_basePath;
  9036. }
  9037. public function setBasePath($value)
  9038. {
  9039. $this->_basePath=$value;
  9040. }
  9041. public function getConfigurationFile()
  9042. {
  9043. return $this->_configFile;
  9044. }
  9045. public function setConfigurationFile($value)
  9046. {
  9047. $this->_configFile=$value;
  9048. }
  9049. public function getRuntimePath()
  9050. {
  9051. return $this->_runtimePath;
  9052. }
  9053. public function setRuntimePath($value)
  9054. {
  9055. $this->_runtimePath=$value;
  9056. if($this->_cacheFile)
  9057. $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
  9058. $this->_uniqueID=md5($this->_runtimePath);
  9059. }
  9060. public function getService()
  9061. {
  9062. return $this->_service;
  9063. }
  9064. public function setService($value)
  9065. {
  9066. $this->_service=$value;
  9067. }
  9068. public function setModule($id,IModule $module)
  9069. {
  9070. if(isset($this->_modules[$id]))
  9071. throw new TConfigurationException('application_moduleid_duplicated',$id);
  9072. else
  9073. $this->_modules[$id]=$module;
  9074. }
  9075. public function getModule($id)
  9076. {
  9077. return isset($this->_modules[$id])?$this->_modules[$id]:null;
  9078. }
  9079. public function getModules()
  9080. {
  9081. return $this->_modules;
  9082. }
  9083. public function getParameters()
  9084. {
  9085. return $this->_parameters;
  9086. }
  9087. public function getRequest()
  9088. {
  9089. if(!$this->_request)
  9090. {
  9091. $this->_request=new THttpRequest;
  9092. $this->_request->init(null);
  9093. }
  9094. return $this->_request;
  9095. }
  9096. public function setRequest(THttpRequest $request)
  9097. {
  9098. $this->_request=$request;
  9099. }
  9100. public function getResponse()
  9101. {
  9102. if(!$this->_response)
  9103. {
  9104. $this->_response=new THttpResponse;
  9105. $this->_response->init(null);
  9106. }
  9107. return $this->_response;
  9108. }
  9109. public function setResponse(THttpResponse $response)
  9110. {
  9111. $this->_response=$response;
  9112. }
  9113. public function getSession()
  9114. {
  9115. if(!$this->_session)
  9116. {
  9117. $this->_session=new THttpSession;
  9118. $this->_session->init(null);
  9119. }
  9120. return $this->_session;
  9121. }
  9122. public function setSession(THttpSession $session)
  9123. {
  9124. $this->_session=$session;
  9125. }
  9126. public function getErrorHandler()
  9127. {
  9128. if(!$this->_errorHandler)
  9129. {
  9130. $this->_errorHandler=new TErrorHandler;
  9131. $this->_errorHandler->init(null);
  9132. }
  9133. return $this->_errorHandler;
  9134. }
  9135. public function setErrorHandler(TErrorHandler $handler)
  9136. {
  9137. $this->_errorHandler=$handler;
  9138. }
  9139. public function getSecurityManager()
  9140. {
  9141. if(!$this->_security)
  9142. {
  9143. $this->_security=new TSecurityManager;
  9144. $this->_security->init(null);
  9145. }
  9146. return $this->_security;
  9147. }
  9148. public function setSecurityManager(TSecurityManager $sm)
  9149. {
  9150. $this->_security=$sm;
  9151. }
  9152. public function getAssetManager()
  9153. {
  9154. if(!$this->_assetManager)
  9155. {
  9156. $this->_assetManager=new TAssetManager;
  9157. $this->_assetManager->init(null);
  9158. }
  9159. return $this->_assetManager;
  9160. }
  9161. public function setAssetManager(TAssetManager $value)
  9162. {
  9163. $this->_assetManager=$value;
  9164. }
  9165. public function getApplicationStatePersister()
  9166. {
  9167. if(!$this->_statePersister)
  9168. {
  9169. $this->_statePersister=new TApplicationStatePersister;
  9170. $this->_statePersister->init(null);
  9171. }
  9172. return $this->_statePersister;
  9173. }
  9174. public function setApplicationStatePersister(IStatePersister $persister)
  9175. {
  9176. $this->_statePersister=$persister;
  9177. }
  9178. public function getCache()
  9179. {
  9180. return $this->_cache;
  9181. }
  9182. public function setCache(ICache $cache)
  9183. {
  9184. $this->_cache=$cache;
  9185. }
  9186. public function getUser()
  9187. {
  9188. return $this->_user;
  9189. }
  9190. public function setUser(IUser $user)
  9191. {
  9192. $this->_user=$user;
  9193. }
  9194. public function getGlobalization($createIfNotExists=true)
  9195. {
  9196. if($this->_globalization===null && $createIfNotExists)
  9197. $this->_globalization=new TGlobalization;
  9198. return $this->_globalization;
  9199. }
  9200. public function setGlobalization(TGlobalization $glob)
  9201. {
  9202. $this->_globalization=$glob;
  9203. }
  9204. public function getAuthorizationRules()
  9205. {
  9206. if($this->_authRules===null)
  9207. $this->_authRules=new TAuthorizationRuleCollection;
  9208. return $this->_authRules;
  9209. }
  9210. public function applyConfiguration($config,$withinService=false)
  9211. {
  9212. if($config->getIsEmpty())
  9213. return;
  9214. foreach($config->getAliases() as $alias=>$path)
  9215. Prado::setPathOfAlias($alias,$path);
  9216. foreach($config->getUsings() as $using)
  9217. Prado::using($using);
  9218. if(!$withinService)
  9219. {
  9220. foreach($config->getProperties() as $name=>$value)
  9221. $this->setSubProperty($name,$value);
  9222. }
  9223. if(empty($this->_services))
  9224. $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
  9225. foreach($config->getParameters() as $id=>$parameter)
  9226. {
  9227. if(is_array($parameter))
  9228. {
  9229. $component=Prado::createComponent($parameter[0]);
  9230. foreach($parameter[1] as $name=>$value)
  9231. $component->setSubProperty($name,$value);
  9232. $this->_parameters->add($id,$component);
  9233. }
  9234. else
  9235. $this->_parameters->add($id,$parameter);
  9236. }
  9237. $modules=array();
  9238. foreach($config->getModules() as $id=>$moduleConfig)
  9239. {
  9240. list($moduleClass, $initProperties, $configElement)=$moduleConfig;
  9241. $module=Prado::createComponent($moduleClass);
  9242. if(!is_string($id))
  9243. {
  9244. $id='_module'.count($this->_modules);
  9245. $initProperties['id']=$id;
  9246. }
  9247. $this->setModule($id,$module);
  9248. foreach($initProperties as $name=>$value)
  9249. $module->setSubProperty($name,$value);
  9250. $modules[]=array($module,$configElement);
  9251. }
  9252. foreach($modules as $module)
  9253. $module[0]->init($module[1]);
  9254. foreach($config->getServices() as $serviceID=>$serviceConfig)
  9255. $this->_services[$serviceID]=$serviceConfig;
  9256. foreach($config->getExternalConfigurations() as $filePath=>$condition)
  9257. {
  9258. if($condition!==true)
  9259. $condition=$this->evaluateExpression($condition);
  9260. if($condition)
  9261. {
  9262. if(($path=Prado::getPathOfNamespace($filePath,self::CONFIG_FILE_EXT))===null || !is_file($path))
  9263. throw new TConfigurationException('application_includefile_invalid',$filePath);
  9264. $c=new TApplicationConfiguration;
  9265. $c->loadFromFile($path);
  9266. $this->applyConfiguration($c,$withinService);
  9267. }
  9268. }
  9269. }
  9270. protected function initApplication()
  9271. {
  9272. if($this->_configFile!==null)
  9273. {
  9274. if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
  9275. {
  9276. $config=new TApplicationConfiguration;
  9277. $config->loadFromFile($this->_configFile);
  9278. if($this->_cacheFile!==null)
  9279. file_put_contents($this->_cacheFile,Prado::serialize($config),LOCK_EX);
  9280. }
  9281. else
  9282. $config=Prado::unserialize(file_get_contents($this->_cacheFile));
  9283. $this->applyConfiguration($config,false);
  9284. }
  9285. if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
  9286. $serviceID=$this->getPageServiceID();
  9287. $this->startService($serviceID);
  9288. }
  9289. public function startService($serviceID)
  9290. {
  9291. if(isset($this->_services[$serviceID]))
  9292. {
  9293. list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
  9294. $service=Prado::createComponent($serviceClass);
  9295. if(!($service instanceof IService))
  9296. throw new THttpException(500,'application_service_invalid',$serviceClass);
  9297. if(!$service->getEnabled())
  9298. throw new THttpException(500,'application_service_unavailable',$serviceClass);
  9299. $service->setID($serviceID);
  9300. $this->setService($service);
  9301. foreach($initProperties as $name=>$value)
  9302. $service->setSubProperty($name,$value);
  9303. if($configElement!==null)
  9304. {
  9305. $config=new TApplicationConfiguration;
  9306. $config->loadFromXml($configElement,$this->getBasePath());
  9307. $this->applyConfiguration($config,true);
  9308. }
  9309. $service->init($configElement);
  9310. }
  9311. else
  9312. throw new THttpException(500,'application_service_unknown',$serviceID);
  9313. }
  9314. public function onError($param)
  9315. {
  9316. Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
  9317. $this->raiseEvent('OnError',$this,$param);
  9318. $this->getErrorHandler()->handleError($this,$param);
  9319. }
  9320. public function onBeginRequest()
  9321. {
  9322. $this->raiseEvent('OnBeginRequest',$this,null);
  9323. }
  9324. public function onAuthentication()
  9325. {
  9326. $this->raiseEvent('OnAuthentication',$this,null);
  9327. }
  9328. public function onAuthenticationComplete()
  9329. {
  9330. $this->raiseEvent('OnAuthenticationComplete',$this,null);
  9331. }
  9332. public function onAuthorization()
  9333. {
  9334. $this->raiseEvent('OnAuthorization',$this,null);
  9335. }
  9336. public function onAuthorizationComplete()
  9337. {
  9338. $this->raiseEvent('OnAuthorizationComplete',$this,null);
  9339. }
  9340. public function onLoadState()
  9341. {
  9342. $this->loadGlobals();
  9343. $this->raiseEvent('OnLoadState',$this,null);
  9344. }
  9345. public function onLoadStateComplete()
  9346. {
  9347. $this->raiseEvent('OnLoadStateComplete',$this,null);
  9348. }
  9349. public function onPreRunService()
  9350. {
  9351. $this->raiseEvent('OnPreRunService',$this,null);
  9352. }
  9353. public function runService()
  9354. {
  9355. if($this->_service)
  9356. $this->_service->run();
  9357. }
  9358. public function onSaveState()
  9359. {
  9360. $this->raiseEvent('OnSaveState',$this,null);
  9361. $this->saveGlobals();
  9362. }
  9363. public function onSaveStateComplete()
  9364. {
  9365. $this->raiseEvent('OnSaveStateComplete',$this,null);
  9366. }
  9367. public function onPreFlushOutput()
  9368. {
  9369. $this->raiseEvent('OnPreFlushOutput',$this,null);
  9370. }
  9371. public function flushOutput()
  9372. {
  9373. $this->getResponse()->flush();
  9374. }
  9375. public function onEndRequest()
  9376. {
  9377. $this->saveGlobals(); $this->raiseEvent('OnEndRequest',$this,null);
  9378. }
  9379. }
  9380. class TApplicationMode extends TEnumerable
  9381. {
  9382. const Off='Off';
  9383. const Debug='Debug';
  9384. const Normal='Normal';
  9385. const Performance='Performance';
  9386. }
  9387. class TApplicationConfiguration extends TComponent
  9388. {
  9389. private $_properties=array();
  9390. private $_usings=array();
  9391. private $_aliases=array();
  9392. private $_modules=array();
  9393. private $_services=array();
  9394. private $_parameters=array();
  9395. private $_includes=array();
  9396. private $_empty=true;
  9397. public function loadFromFile($fname)
  9398. {
  9399. $dom=new TXmlDocument;
  9400. $dom->loadFromFile($fname);
  9401. $this->loadFromXml($dom,dirname($fname));
  9402. }
  9403. public function getIsEmpty()
  9404. {
  9405. return $this->_empty;
  9406. }
  9407. public function loadFromXml($dom,$configPath)
  9408. {
  9409. foreach($dom->getAttributes() as $name=>$value)
  9410. {
  9411. $this->_properties[$name]=$value;
  9412. $this->_empty=false;
  9413. }
  9414. foreach($dom->getElements() as $element)
  9415. {
  9416. switch($element->getTagName())
  9417. {
  9418. case 'paths':
  9419. $this->loadPathsXml($element,$configPath);
  9420. break;
  9421. case 'modules':
  9422. $this->loadModulesXml($element,$configPath);
  9423. break;
  9424. case 'services':
  9425. $this->loadServicesXml($element,$configPath);
  9426. break;
  9427. case 'parameters':
  9428. $this->loadParametersXml($element,$configPath);
  9429. break;
  9430. case 'include':
  9431. $this->loadExternalXml($element,$configPath);
  9432. break;
  9433. default:
  9434. break;
  9435. }
  9436. }
  9437. }
  9438. protected function loadPathsXml($pathsNode,$configPath)
  9439. {
  9440. foreach($pathsNode->getElements() as $element)
  9441. {
  9442. switch($element->getTagName())
  9443. {
  9444. case 'alias':
  9445. {
  9446. if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
  9447. {
  9448. $path=str_replace('\\','/',$path);
  9449. if(preg_match('/^\\/|.:\\/|.:\\\\/',$path)) $p=realpath($path);
  9450. else
  9451. $p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
  9452. if($p===false || !is_dir($p))
  9453. throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
  9454. if(isset($this->_aliases[$id]))
  9455. throw new TConfigurationException('appconfig_alias_redefined',$id);
  9456. $this->_aliases[$id]=$p;
  9457. }
  9458. else
  9459. throw new TConfigurationException('appconfig_alias_invalid');
  9460. $this->_empty=false;
  9461. break;
  9462. }
  9463. case 'using':
  9464. {
  9465. if(($namespace=$element->getAttribute('namespace'))!==null)
  9466. $this->_usings[]=$namespace;
  9467. else
  9468. throw new TConfigurationException('appconfig_using_invalid');
  9469. $this->_empty=false;
  9470. break;
  9471. }
  9472. default:
  9473. throw new TConfigurationException('appconfig_paths_invalid',$element->getTagName());
  9474. }
  9475. }
  9476. }
  9477. protected function loadModulesXml($modulesNode,$configPath)
  9478. {
  9479. foreach($modulesNode->getElements() as $element)
  9480. {
  9481. if($element->getTagName()==='module')
  9482. {
  9483. $properties=$element->getAttributes();
  9484. $id=$properties->itemAt('id');
  9485. $type=$properties->remove('class');
  9486. if($type===null)
  9487. throw new TConfigurationException('appconfig_moduletype_required',$id);
  9488. $element->setParent(null);
  9489. if($id===null)
  9490. $this->_modules[]=array($type,$properties->toArray(),$element);
  9491. else
  9492. $this->_modules[$id]=array($type,$properties->toArray(),$element);
  9493. $this->_empty=false;
  9494. }
  9495. else
  9496. throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
  9497. }
  9498. }
  9499. protected function loadServicesXml($servicesNode,$configPath)
  9500. {
  9501. foreach($servicesNode->getElements() as $element)
  9502. {
  9503. if($element->getTagName()==='service')
  9504. {
  9505. $properties=$element->getAttributes();
  9506. if(($id=$properties->itemAt('id'))===null)
  9507. throw new TConfigurationException('appconfig_serviceid_required');
  9508. if(($type=$properties->remove('class'))===null)
  9509. throw new TConfigurationException('appconfig_servicetype_required',$id);
  9510. $element->setParent(null);
  9511. $this->_services[$id]=array($type,$properties->toArray(),$element);
  9512. $this->_empty=false;
  9513. }
  9514. else
  9515. throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
  9516. }
  9517. }
  9518. protected function loadParametersXml($parametersNode,$configPath)
  9519. {
  9520. foreach($parametersNode->getElements() as $element)
  9521. {
  9522. if($element->getTagName()==='parameter')
  9523. {
  9524. $properties=$element->getAttributes();
  9525. if(($id=$properties->remove('id'))===null)
  9526. throw new TConfigurationException('appconfig_parameterid_required');
  9527. if(($type=$properties->remove('class'))===null)
  9528. {
  9529. if(($value=$properties->remove('value'))===null)
  9530. $this->_parameters[$id]=$element;
  9531. else
  9532. $this->_parameters[$id]=$value;
  9533. }
  9534. else
  9535. $this->_parameters[$id]=array($type,$properties->toArray());
  9536. $this->_empty=false;
  9537. }
  9538. else
  9539. throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
  9540. }
  9541. }
  9542. protected function loadExternalXml($includeNode,$configPath)
  9543. {
  9544. if(($when=$includeNode->getAttribute('when'))===null)
  9545. $when=true;
  9546. if(($filePath=$includeNode->getAttribute('file'))===null)
  9547. throw new TConfigurationException('appconfig_includefile_required');
  9548. if(isset($this->_includes[$filePath]))
  9549. $this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
  9550. else
  9551. $this->_includes[$filePath]=$when;
  9552. $this->_empty=false;
  9553. }
  9554. public function getProperties()
  9555. {
  9556. return $this->_properties;
  9557. }
  9558. public function getAliases()
  9559. {
  9560. return $this->_aliases;
  9561. }
  9562. public function getUsings()
  9563. {
  9564. return $this->_usings;
  9565. }
  9566. public function getModules()
  9567. {
  9568. return $this->_modules;
  9569. }
  9570. public function getServices()
  9571. {
  9572. return $this->_services;
  9573. }
  9574. public function getParameters()
  9575. {
  9576. return $this->_parameters;
  9577. }
  9578. public function getExternalConfigurations()
  9579. {
  9580. return $this->_includes;
  9581. }
  9582. }
  9583. class TApplicationStatePersister extends TModule implements IStatePersister
  9584. {
  9585. const CACHE_NAME='prado:appstate';
  9586. public function init($config)
  9587. {
  9588. $this->getApplication()->setApplicationStatePersister($this);
  9589. }
  9590. protected function getStateFilePath()
  9591. {
  9592. return $this->getApplication()->getRuntimePath().'/global.cache';
  9593. }
  9594. public function load()
  9595. {
  9596. if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
  9597. return unserialize($value);
  9598. else
  9599. {
  9600. if(($content=@file_get_contents($this->getStateFilePath()))!==false)
  9601. return unserialize($content);
  9602. else
  9603. return null;
  9604. }
  9605. }
  9606. public function save($state)
  9607. {
  9608. $content=serialize($state);
  9609. $saveFile=true;
  9610. if(($cache=$this->getApplication()->getCache())!==null)
  9611. {
  9612. if($cache->get(self::CACHE_NAME)===$content)
  9613. $saveFile=false;
  9614. else
  9615. $cache->set(self::CACHE_NAME,$content);
  9616. }
  9617. if($saveFile)
  9618. {
  9619. $fileName=$this->getStateFilePath();
  9620. file_put_contents($fileName,$content,LOCK_EX);
  9621. }
  9622. }
  9623. }
  9624. class TShellApplication extends TApplication
  9625. {
  9626. public function startService($serviceID)
  9627. {
  9628. }
  9629. public function run()
  9630. {
  9631. $this->initApplication();
  9632. }
  9633. }
  9634. ?>