summaryrefslogtreecommitdiff
path: root/lib/prado/framework/pradolite.php
diff options
context:
space:
mode:
authoremkael <emkael@tlen.pl>2016-02-24 23:18:07 +0100
committeremkael <emkael@tlen.pl>2016-02-24 23:18:07 +0100
commit6f7fdef0f500cd4bb540affd3bc1482243f337c1 (patch)
tree4853eecd0769a903e6130c1896e1d070848150dd /lib/prado/framework/pradolite.php
parent61f2ea48a4e11cb5fb941b3783e19c9e9ef38a45 (diff)
* Prado 3.3.0
Diffstat (limited to 'lib/prado/framework/pradolite.php')
-rw-r--r--lib/prado/framework/pradolite.php11236
1 files changed, 11236 insertions, 0 deletions
diff --git a/lib/prado/framework/pradolite.php b/lib/prado/framework/pradolite.php
new file mode 100644
index 0000000..bdbf113
--- /dev/null
+++ b/lib/prado/framework/pradolite.php
@@ -0,0 +1,11236 @@
+<?php
+/**
+ * File Name: pradolite.php
+ * Last Update: 2015/12/07 15:35:09
+ * Generated By: buildscripts/phpbuilder/build.php
+ *
+ * This file is used in lieu of prado.php to boost PRADO application performance.
+ * It is generated by expanding prado.php with included files.
+ * Comments and trace statements are stripped off.
+ *
+ * Do not modify this file manually.
+ */
+
+if(!defined('PRADO_DIR'))
+ define('PRADO_DIR',dirname(__FILE__));
+if(!defined('PRADO_CHMOD'))
+ define('PRADO_CHMOD',0777);
+class PradoBase
+{
+ const CLASS_FILE_EXT='.php';
+ private static $_aliases=array('System'=>PRADO_DIR);
+ private static $_usings=array();
+ private static $_application=null;
+ private static $_logger=null;
+ protected static $classExists = array();
+ public static function getVersion()
+ {
+ return '3.3.0';
+ }
+ public static function initErrorHandlers()
+ {
+ set_error_handler(array('PradoBase','phpErrorHandler'));
+ set_exception_handler(array('PradoBase','exceptionHandler'));
+ }
+ public static function autoload($className)
+ {
+ include_once($className.self::CLASS_FILE_EXT);
+ if(!class_exists($className,false) && !interface_exists($className,false))
+ self::fatalError("Class file for '$className' cannot be found.");
+ }
+ public static function poweredByPrado($logoType=0)
+ {
+ $logoName=$logoType==1?'powered2':'powered';
+ if(self::$_application!==null)
+ {
+ $am=self::$_application->getAssetManager();
+ $url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
+ }
+ else
+ $url='http://pradosoft.github.io/docs/'.$logoName.'.gif';
+ return '<a title="Powered by PRADO" href="https://github.com/pradosoft/prado" target="_blank"><img src="'.$url.'" style="border-width:0px;" alt="Powered by PRADO" /></a>';
+ }
+ public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
+ {
+ if(error_reporting() & $errno)
+ throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
+ }
+ public static function exceptionHandler($exception)
+ {
+ if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
+ {
+ $errorHandler->handleError(null,$exception);
+ }
+ else
+ {
+ echo $exception;
+ }
+ exit(1);
+ }
+ public static function setApplication($application)
+ {
+ if(self::$_application!==null && !defined('PRADO_TEST_RUN'))
+ throw new TInvalidOperationException('prado_application_singleton_required');
+ self::$_application=$application;
+ }
+ public static function getApplication()
+ {
+ return self::$_application;
+ }
+ public static function getFrameworkPath()
+ {
+ return PRADO_DIR;
+ }
+ public static function createComponent($type)
+ {
+ if(!isset(self::$classExists[$type]))
+ self::$classExists[$type] = class_exists($type, false);
+ if( !isset(self::$_usings[$type]) && !self::$classExists[$type]) {
+ self::using($type);
+ self::$classExists[$type] = class_exists($type, false);
+ }
+ if( ($pos = strrpos($type, '.')) !== false)
+ $type = substr($type,$pos+1);
+ if(($n=func_num_args())>1)
+ {
+ $args = func_get_args();
+ switch($n) {
+ case 2:
+ return new $type($args[1]);
+ break;
+ case 3:
+ return new $type($args[1], $args[2]);
+ break;
+ case 4:
+ return new $type($args[1], $args[2], $args[3]);
+ break;
+ case 5:
+ return new $type($args[1], $args[2], $args[3], $args[4]);
+ break;
+ default:
+ $s='$args[1]';
+ for($i=2;$i<$n;++$i)
+ $s.=",\$args[$i]";
+ eval("\$component=new $type($s);");
+ return $component;
+ break;
+ }
+ }
+ else
+ return new $type;
+ }
+ public static function using($namespace,$checkClassExistence=true)
+ {
+ if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
+ return;
+ if(($pos=strrpos($namespace,'.'))===false) {
+ try
+ {
+ include_once($namespace.self::CLASS_FILE_EXT);
+ }
+ catch(Exception $e)
+ {
+ if($checkClassExistence && !class_exists($namespace,false))
+ throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
+ else
+ throw $e;
+ }
+ }
+ else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
+ {
+ $className=substr($namespace,$pos+1);
+ if($className==='*') {
+ self::$_usings[$namespace]=$path;
+ set_include_path(get_include_path().PATH_SEPARATOR.$path);
+ }
+ else {
+ self::$_usings[$namespace]=$path;
+ if(!$checkClassExistence || !class_exists($className,false))
+ {
+ try
+ {
+ include_once($path);
+ }
+ catch(Exception $e)
+ {
+ if($checkClassExistence && !class_exists($className,false))
+ throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
+ else
+ throw $e;
+ }
+ }
+ }
+ }
+ else
+ throw new TInvalidDataValueException('prado_using_invalid',$namespace);
+ }
+ public static function getPathOfNamespace($namespace, $ext='')
+ {
+ if(self::CLASS_FILE_EXT === $ext || empty($ext))
+ {
+ if(isset(self::$_usings[$namespace]))
+ return self::$_usings[$namespace];
+ if(isset(self::$_aliases[$namespace]))
+ return self::$_aliases[$namespace];
+ }
+ $segs = explode('.',$namespace);
+ $alias = array_shift($segs);
+ if(null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias)))
+ return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file === '*') ? '' : DIRECTORY_SEPARATOR.$file.$ext);
+ return null;
+ }
+ public static function getPathOfAlias($alias)
+ {
+ return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
+ }
+ protected static function getPathAliases()
+ {
+ return self::$_aliases;
+ }
+ public static function setPathOfAlias($alias,$path)
+ {
+ if(isset(self::$_aliases[$alias]) && !defined('PRADO_TEST_RUN'))
+ throw new TInvalidOperationException('prado_alias_redefined',$alias);
+ else if(($rp=realpath($path))!==false && is_dir($rp))
+ {
+ if(strpos($alias,'.')===false)
+ self::$_aliases[$alias]=$rp;
+ else
+ throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
+ }
+ else
+ throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
+ }
+ public static function fatalError($msg)
+ {
+ echo '<h1>Fatal Error</h1>';
+ echo '<p>'.$msg.'</p>';
+ if(!function_exists('debug_backtrace'))
+ return;
+ echo '<h2>Debug Backtrace</h2>';
+ echo '<pre>';
+ $index=-1;
+ foreach(debug_backtrace() as $t)
+ {
+ $index++;
+ if($index==0) continue;
+ echo '#'.$index.' ';
+ if(isset($t['file']))
+ echo basename($t['file']) . ':' . $t['line'];
+ else
+ echo '<PHP inner-code>';
+ echo ' -- ';
+ if(isset($t['class']))
+ echo $t['class'] . $t['type'];
+ echo $t['function'] . '(';
+ if(isset($t['args']) && sizeof($t['args']) > 0)
+ {
+ $count=0;
+ foreach($t['args'] as $item)
+ {
+ if(is_string($item))
+ {
+ $str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
+ if (strlen($item) > 70)
+ echo "'". substr($str, 0, 70) . "...'";
+ else
+ echo "'" . $str . "'";
+ }
+ else if (is_int($item) || is_float($item))
+ echo $item;
+ else if (is_object($item))
+ echo get_class($item);
+ else if (is_array($item))
+ echo 'array(' . count($item) . ')';
+ else if (is_bool($item))
+ echo $item ? 'true' : 'false';
+ else if ($item === null)
+ echo 'NULL';
+ else if (is_resource($item))
+ echo get_resource_type($item);
+ $count++;
+ if (count($t['args']) > $count)
+ echo ', ';
+ }
+ }
+ echo ")\n";
+ }
+ echo '</pre>';
+ exit(1);
+ }
+ public static function getUserLanguages()
+ {
+ static $languages=null;
+ if($languages===null)
+ {
+ if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
+ $languages[0]='en';
+ else
+ {
+ $languages=array();
+ foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
+ {
+ $array=explode(';q=',trim($language));
+ $languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
+ }
+ arsort($languages);
+ $languages=array_keys($languages);
+ if(empty($languages))
+ $languages[0]='en';
+ }
+ }
+ return $languages;
+ }
+ public static function getPreferredLanguage()
+ {
+ static $language=null;
+ if($language===null)
+ {
+ $langs=Prado::getUserLanguages();
+ $lang=explode('-',$langs[0]);
+ if(empty($lang[0]) || !ctype_alpha($lang[0]))
+ $language='en';
+ else
+ $language=$lang[0];
+ }
+ return $language;
+ }
+ public static function trace($msg,$category='Uncategorized',$ctl=null)
+ {
+ if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
+ return;
+ if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
+ {
+ $trace=debug_backtrace();
+ if(isset($trace[0]['file']) && isset($trace[0]['line']))
+ $msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
+ $level=TLogger::DEBUG;
+ }
+ else
+ $level=TLogger::INFO;
+ self::log($msg,$level,$category,$ctl);
+ }
+ public static function log($msg,$level=TLogger::INFO,$category='Uncategorized',$ctl=null)
+ {
+ if(self::$_logger===null)
+ self::$_logger=new TLogger;
+ self::$_logger->log($msg,$level,$category,$ctl);
+ }
+ public static function getLogger()
+ {
+ if(self::$_logger===null)
+ self::$_logger=new TLogger;
+ return self::$_logger;
+ }
+ public static function varDump($var,$depth=10,$highlight=false)
+ {
+ Prado::using('System.Util.TVarDumper');
+ return TVarDumper::dump($var,$depth,$highlight);
+ }
+ public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
+ {
+ Prado::using('System.I18N.Translation');
+ $app = Prado::getApplication()->getGlobalization(false);
+ $params = array();
+ foreach($parameters as $key => $value)
+ $params['{'.$key.'}'] = $value;
+ if($app===null || ($config = $app->getTranslationConfiguration())===null)
+ return strtr($text, $params);
+ if ($catalogue===null)
+ $catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
+ Translation::init($catalogue);
+ $appCharset = $app===null ? '' : $app->getCharset();
+ $defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
+ if(empty($charset)) $charset = $appCharset;
+ if(empty($charset)) $charset = $defaultCharset;
+ return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset);
+ }
+}
+PradoBase::using('System.TComponent');
+PradoBase::using('System.Exceptions.TException');
+PradoBase::using('System.Util.TLogger');
+if(!class_exists('Prado',false))
+{
+ class Prado extends PradoBase
+ {
+ }
+}
+spl_autoload_register(array('Prado','autoload'));
+Prado::initErrorHandlers();
+interface IModule
+{
+ public function init($config);
+ public function getID();
+ public function setID($id);
+}
+interface IService
+{
+ public function init($config);
+ public function getID();
+ public function setID($id);
+ public function getEnabled();
+ public function setEnabled($value);
+ public function run();
+}
+interface ITextWriter
+{
+ public function write($str);
+ public function flush();
+}
+interface IUser
+{
+ public function getName();
+ public function setName($value);
+ public function getIsGuest();
+ public function setIsGuest($value);
+ public function getRoles();
+ public function setRoles($value);
+ public function isInRole($role);
+ public function saveToString();
+ public function loadFromString($string);
+}
+interface IStatePersister
+{
+ public function load();
+ public function save($state);
+}
+interface ICache
+{
+ public function get($id);
+ public function set($id,$value,$expire=0,$dependency=null);
+ public function add($id,$value,$expire=0,$dependency=null);
+ public function delete($id);
+ public function flush();
+}
+interface ICacheDependency
+{
+ public function getHasChanged();
+}
+interface IRenderable
+{
+ public function render($writer);
+}
+interface IBindable
+{
+ public function dataBind();
+}
+interface IStyleable
+{
+ public function getHasStyle();
+ public function getStyle();
+ public function clearStyle();
+}
+interface IActiveControl
+{
+ public function getActiveControl();
+}
+interface ICallbackEventHandler
+{
+ public function raiseCallbackEvent($eventArgument);
+}
+interface IDataRenderer
+{
+ public function getData();
+ public function setData($value);
+}
+class TApplicationComponent extends TComponent
+{
+ public function getApplication()
+ {
+ return Prado::getApplication();
+ }
+ public function getService()
+ {
+ return Prado::getApplication()->getService();
+ }
+ public function getRequest()
+ {
+ return Prado::getApplication()->getRequest();
+ }
+ public function getResponse()
+ {
+ return Prado::getApplication()->getResponse();
+ }
+ public function getSession()
+ {
+ return Prado::getApplication()->getSession();
+ }
+ public function getUser()
+ {
+ return Prado::getApplication()->getUser();
+ }
+ public function publishAsset($assetPath,$className=null)
+ {
+ if($className===null)
+ $className=get_class($this);
+ $class=new ReflectionClass($className);
+ $fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath;
+ return $this->publishFilePath($fullPath);
+ }
+ public function publishFilePath($fullPath, $checkTimestamp=false)
+ {
+ return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath, $checkTimestamp);
+ }
+}
+abstract class TModule extends TApplicationComponent implements IModule
+{
+ private $_id;
+ public function init($config)
+ {
+ }
+ public function getID()
+ {
+ return $this->_id;
+ }
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+}
+abstract class TService extends TApplicationComponent implements IService
+{
+ private $_id;
+ private $_enabled=true;
+ public function init($config)
+ {
+ }
+ public function getID()
+ {
+ return $this->_id;
+ }
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+ public function getEnabled()
+ {
+ return $this->_enabled;
+ }
+ public function setEnabled($value)
+ {
+ $this->_enabled=TPropertyValue::ensureBoolean($value);
+ }
+ public function run()
+ {
+ }
+}
+class TErrorHandler extends TModule
+{
+ const ERROR_FILE_NAME='error';
+ const EXCEPTION_FILE_NAME='exception';
+ const SOURCE_LINES=12;
+ private $_templatePath=null;
+ public function init($config)
+ {
+ $this->getApplication()->setErrorHandler($this);
+ }
+ public function getErrorTemplatePath()
+ {
+ if($this->_templatePath===null)
+ $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
+ return $this->_templatePath;
+ }
+ public function setErrorTemplatePath($value)
+ {
+ if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath))
+ $this->_templatePath=$templatePath;
+ else
+ throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value);
+ }
+ public function handleError($sender,$param)
+ {
+ static $handling=false;
+ restore_error_handler();
+ restore_exception_handler();
+ if($handling)
+ $this->handleRecursiveError($param);
+ else
+ {
+ $handling=true;
+ if(($response=$this->getResponse())!==null)
+ $response->clear();
+ if(!headers_sent())
+ header('Content-Type: text/html; charset=UTF-8');
+ if($param instanceof THttpException)
+ $this->handleExternalError($param->getStatusCode(),$param);
+ else if($this->getApplication()->getMode()===TApplicationMode::Debug)
+ $this->displayException($param);
+ else
+ $this->handleExternalError(500,$param);
+ }
+ }
+ protected static function hideSecurityRelated($value, $exception=null)
+ {
+ $aRpl = array();
+ if($exception !== null && $exception instanceof Exception)
+ {
+ $aTrace = $exception->getTrace();
+ foreach($aTrace as $item)
+ {
+ if(isset($item['file']))
+ $aRpl[dirname($item['file']) . DIRECTORY_SEPARATOR] = '<hidden>' . DIRECTORY_SEPARATOR;
+ }
+ }
+ $aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}';
+ $aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}';
+ $aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR;
+ if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]);
+ $aRpl = array_reverse($aRpl, true);
+ return str_replace(array_keys($aRpl), $aRpl, $value);
+ }
+ protected function handleExternalError($statusCode,$exception)
+ {
+ if(!($exception instanceof THttpException))
+ error_log($exception->__toString());
+ $content=$this->getErrorTemplate($statusCode,$exception);
+ $serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
+ $isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug;
+ $errorMessage = $exception->getMessage();
+ if($isDebug)
+ $version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
+ else
+ {
+ $version='';
+ $errorMessage = self::hideSecurityRelated($errorMessage, $exception);
+ }
+ $tokens=array(
+ '%%StatusCode%%' => "$statusCode",
+ '%%ErrorMessage%%' => htmlspecialchars($errorMessage),
+ '%%ServerAdmin%%' => $serverAdmin,
+ '%%Version%%' => $version,
+ '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
+ );
+ $this->getApplication()->getResponse()->setStatusCode($statusCode, $isDebug ? $exception->getMessage() : null);
+ echo strtr($content,$tokens);
+ }
+ protected function handleRecursiveError($exception)
+ {
+ if($this->getApplication()->getMode()===TApplicationMode::Debug)
+ {
+ echo "<html><head><title>Recursive Error</title></head>\n";
+ echo "<body><h1>Recursive Error</h1>\n";
+ echo "<pre>".$exception->__toString()."</pre>\n";
+ echo "</body></html>";
+ }
+ else
+ {
+ error_log("Error happened while processing an existing error:\n".$exception->__toString());
+ header('HTTP/1.0 500 Internal Error');
+ }
+ }
+ protected function displayException($exception)
+ {
+ if(php_sapi_name()==='cli')
+ {
+ echo $exception->getMessage()."\n";
+ echo $exception->getTraceAsString();
+ return;
+ }
+ if($exception instanceof TTemplateException)
+ {
+ $fileName=$exception->getTemplateFile();
+ $lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
+ $source=$this->getSourceCode($lines,$exception->getLineNumber());
+ if($fileName==='')
+ $fileName='---embedded template---';
+ $errorLine=$exception->getLineNumber();
+ }
+ else
+ {
+ if(($trace=$this->getExactTrace($exception))!==null)
+ {
+ $fileName=$trace['file'];
+ $errorLine=$trace['line'];
+ }
+ else
+ {
+ $fileName=$exception->getFile();
+ $errorLine=$exception->getLine();
+ }
+ $source=$this->getSourceCode(@file($fileName),$errorLine);
+ }
+ if($this->getApplication()->getMode()===TApplicationMode::Debug)
+ $version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
+ else
+ $version='';
+ $tokens=array(
+ '%%ErrorType%%' => get_class($exception),
+ '%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
+ '%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
+ '%%SourceCode%%' => $source,
+ '%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
+ '%%Version%%' => $version,
+ '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
+ );
+ $content=$this->getExceptionTemplate($exception);
+ echo strtr($content,$tokens);
+ }
+ protected function getExceptionTemplate($exception)
+ {
+ $lang=Prado::getPreferredLanguage();
+ $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html';
+ if(!is_file($exceptionFile))
+ $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html';
+ if(($content=@file_get_contents($exceptionFile))===false)
+ die("Unable to open exception template file '$exceptionFile'.");
+ return $content;
+ }
+ protected function getErrorTemplate($statusCode,$exception)
+ {
+ $base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME;
+ $lang=Prado::getPreferredLanguage();
+ if(is_file("$base$statusCode-$lang.html"))
+ $errorFile="$base$statusCode-$lang.html";
+ else if(is_file("$base$statusCode.html"))
+ $errorFile="$base$statusCode.html";
+ else if(is_file("$base-$lang.html"))
+ $errorFile="$base-$lang.html";
+ else
+ $errorFile="$base.html";
+ if(($content=@file_get_contents($errorFile))===false)
+ die("Unable to open error template file '$errorFile'.");
+ return $content;
+ }
+ private function getExactTrace($exception)
+ {
+ $trace=$exception->getTrace();
+ $result=null;
+ if($exception instanceof TPhpErrorException)
+ $result=isset($trace[0]['file'])?$trace[0]:$trace[1];
+ else if($exception instanceof TInvalidOperationException)
+ {
+ if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
+ $result=$this->getPropertyAccessTrace($trace,'__set');
+ }
+ if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
+ return null;
+ return $result;
+ }
+ private function getPropertyAccessTrace($trace,$pattern)
+ {
+ $result=null;
+ foreach($trace as $t)
+ {
+ if(isset($t['function']) && $t['function']===$pattern)
+ $result=$t;
+ else
+ break;
+ }
+ return $result;
+ }
+ private function getSourceCode($lines,$errorLine)
+ {
+ $beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
+ $endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
+ $source='';
+ for($i=$beginLine;$i<$endLine;++$i)
+ {
+ if($i===$errorLine-1)
+ {
+ $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
+ $source.="<div class=\"error\">".$line."</div>";
+ }
+ else
+ $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
+ }
+ return $source;
+ }
+ private function addLink($message)
+ {
+ $baseUrl='http://pradosoft.github.io/docs/manual/class-';
+ return preg_replace('/\b(T[A-Z]\w+)\b/',"<a href=\"$baseUrl/\${1}\" target=\"_blank\">\${1}</a>",$message);
+ }
+}
+class TList extends TComponent implements IteratorAggregate,ArrayAccess,Countable
+{
+ private $_d=array();
+ private $_c=0;
+ private $_r=false;
+ public function __construct($data=null,$readOnly=false)
+ {
+ if($data!==null)
+ $this->copyFrom($data);
+ $this->setReadOnly($readOnly);
+ }
+ public function getReadOnly()
+ {
+ return $this->_r;
+ }
+ protected function setReadOnly($value)
+ {
+ $this->_r=TPropertyValue::ensureBoolean($value);
+ }
+ public function getIterator()
+ {
+ return new ArrayIterator( $this->_d );
+ }
+ public function count()
+ {
+ return $this->getCount();
+ }
+ public function getCount()
+ {
+ return $this->_c;
+ }
+ public function itemAt($index)
+ {
+ if($index>=0 && $index<$this->_c)
+ return $this->_d[$index];
+ else
+ throw new TInvalidDataValueException('list_index_invalid',$index);
+ }
+ public function add($item)
+ {
+ $this->insertAt($this->_c,$item);
+ return $this->_c-1;
+ }
+ public function insertAt($index,$item)
+ {
+ if(!$this->_r)
+ {
+ if($index===$this->_c)
+ $this->_d[$this->_c++]=$item;
+ else if($index>=0 && $index<$this->_c)
+ {
+ array_splice($this->_d,$index,0,array($item));
+ $this->_c++;
+ }
+ else
+ throw new TInvalidDataValueException('list_index_invalid',$index);
+ }
+ else
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ }
+ public function remove($item)
+ {
+ if(!$this->_r)
+ {
+ if(($index=$this->indexOf($item))>=0)
+ {
+ $this->removeAt($index);
+ return $index;
+ }
+ else
+ throw new TInvalidDataValueException('list_item_inexistent');
+ }
+ else
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ }
+ public function removeAt($index)
+ {
+ if(!$this->_r)
+ {
+ if($index>=0 && $index<$this->_c)
+ {
+ $this->_c--;
+ if($index===$this->_c)
+ return array_pop($this->_d);
+ else
+ {
+ $item=$this->_d[$index];
+ array_splice($this->_d,$index,1);
+ return $item;
+ }
+ }
+ else
+ throw new TInvalidDataValueException('list_index_invalid',$index);
+ }
+ else
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ }
+ public function clear()
+ {
+ for($i=$this->_c-1;$i>=0;--$i)
+ $this->removeAt($i);
+ }
+ public function contains($item)
+ {
+ return $this->indexOf($item)>=0;
+ }
+ public function indexOf($item)
+ {
+ if(($index=array_search($item,$this->_d,true))===false)
+ return -1;
+ else
+ return $index;
+ }
+ public function insertBefore($baseitem, $item)
+ {
+ if(!$this->_r)
+ {
+ if(($index = $this->indexOf($baseitem)) == -1)
+ throw new TInvalidDataValueException('list_item_inexistent');
+ $this->insertAt($index, $item);
+ return $index;
+ }
+ else
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ }
+ public function insertAfter($baseitem, $item)
+ {
+ if(!$this->_r)
+ {
+ if(($index = $this->indexOf($baseitem)) == -1)
+ throw new TInvalidDataValueException('list_item_inexistent');
+ $this->insertAt($index + 1, $item);
+ return $index + 1;
+ }
+ else
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ }
+ public function toArray()
+ {
+ return $this->_d;
+ }
+ public function copyFrom($data)
+ {
+ if(is_array($data) || ($data instanceof Traversable))
+ {
+ if($this->_c>0)
+ $this->clear();
+ foreach($data as $item)
+ $this->add($item);
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('list_data_not_iterable');
+ }
+ public function mergeWith($data)
+ {
+ if(is_array($data) || ($data instanceof Traversable))
+ {
+ foreach($data as $item)
+ $this->add($item);
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('list_data_not_iterable');
+ }
+ public function offsetExists($offset)
+ {
+ return ($offset>=0 && $offset<$this->_c);
+ }
+ public function offsetGet($offset)
+ {
+ return $this->itemAt($offset);
+ }
+ public function offsetSet($offset,$item)
+ {
+ if($offset===null || $offset===$this->_c)
+ $this->insertAt($this->_c,$item);
+ else
+ {
+ $this->removeAt($offset);
+ $this->insertAt($offset,$item);
+ }
+ }
+ public function offsetUnset($offset)
+ {
+ $this->removeAt($offset);
+ }
+}
+class TListIterator implements Iterator
+{
+ private $_d;
+ private $_i;
+ private $_c;
+ public function __construct(&$data)
+ {
+ $this->_d=&$data;
+ $this->_i=0;
+ $this->_c=count($this->_d);
+ }
+ public function rewind()
+ {
+ $this->_i=0;
+ }
+ public function key()
+ {
+ return $this->_i;
+ }
+ public function current()
+ {
+ return $this->_d[$this->_i];
+ }
+ public function next()
+ {
+ $this->_i++;
+ }
+ public function valid()
+ {
+ return $this->_i<$this->_c;
+ }
+}
+abstract class TCache extends TModule implements ICache, ArrayAccess
+{
+ private $_prefix=null;
+ private $_primary=true;
+ public function init($config)
+ {
+ if($this->_prefix===null)
+ $this->_prefix=$this->getApplication()->getUniqueID();
+ if($this->_primary)
+ {
+ if($this->getApplication()->getCache()===null)
+ $this->getApplication()->setCache($this);
+ else
+ throw new TConfigurationException('cache_primary_duplicated',get_class($this));
+ }
+ }
+ public function getPrimaryCache()
+ {
+ return $this->_primary;
+ }
+ public function setPrimaryCache($value)
+ {
+ $this->_primary=TPropertyValue::ensureBoolean($value);
+ }
+ public function getKeyPrefix()
+ {
+ return $this->_prefix;
+ }
+ public function setKeyPrefix($value)
+ {
+ $this->_prefix=$value;
+ }
+ protected function generateUniqueKey($key)
+ {
+ return md5($this->_prefix.$key);
+ }
+ public function get($id)
+ {
+ if(($data=$this->getValue($this->generateUniqueKey($id)))!==false)
+ {
+ if(!is_array($data))
+ return false;
+ if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
+ return $data[0];
+ }
+ return false;
+ }
+ public function set($id,$value,$expire=0,$dependency=null)
+ {
+ if(empty($value) && $expire === 0)
+ $this->delete($id);
+ else
+ {
+ $data=array($value,$dependency);
+ return $this->setValue($this->generateUniqueKey($id),$data,$expire);
+ }
+ }
+ public function add($id,$value,$expire=0,$dependency=null)
+ {
+ if(empty($value) && $expire === 0)
+ return false;
+ $data=array($value,$dependency);
+ return $this->addValue($this->generateUniqueKey($id),$data,$expire);
+ }
+ public function delete($id)
+ {
+ return $this->deleteValue($this->generateUniqueKey($id));
+ }
+ public function flush()
+ {
+ throw new TNotSupportedException('cache_flush_unsupported');
+ }
+ abstract protected function getValue($key);
+ abstract protected function setValue($key,$value,$expire);
+ abstract protected function addValue($key,$value,$expire);
+ abstract protected function deleteValue($key);
+ public function offsetExists($id)
+ {
+ return $this->get($id) !== false;
+ }
+ public function offsetGet($id)
+ {
+ return $this->get($id);
+ }
+ public function offsetSet($id, $value)
+ {
+ $this->set($id, $value);
+ }
+ public function offsetUnset($id)
+ {
+ $this->delete($id);
+ }
+}
+abstract class TCacheDependency extends TComponent implements ICacheDependency
+{
+}
+class TFileCacheDependency extends TCacheDependency
+{
+ private $_fileName;
+ private $_timestamp;
+ public function __construct($fileName)
+ {
+ $this->setFileName($fileName);
+ }
+ public function getFileName()
+ {
+ return $this->_fileName;
+ }
+ public function setFileName($value)
+ {
+ $this->_fileName=$value;
+ $this->_timestamp=@filemtime($value);
+ }
+ public function getTimestamp()
+ {
+ return $this->_timestamp;
+ }
+ public function getHasChanged()
+ {
+ return @filemtime($this->_fileName)!==$this->_timestamp;
+ }
+}
+class TDirectoryCacheDependency extends TCacheDependency
+{
+ private $_recursiveCheck=true;
+ private $_recursiveLevel=-1;
+ private $_timestamps;
+ private $_directory;
+ public function __construct($directory)
+ {
+ $this->setDirectory($directory);
+ }
+ public function getDirectory()
+ {
+ return $this->_directory;
+ }
+ public function setDirectory($directory)
+ {
+ if(($path=realpath($directory))===false || !is_dir($path))
+ throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
+ $this->_directory=$path;
+ $this->_timestamps=$this->generateTimestamps($path);
+ }
+ public function getRecursiveCheck()
+ {
+ return $this->_recursiveCheck;
+ }
+ public function setRecursiveCheck($value)
+ {
+ $this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
+ }
+ public function getRecursiveLevel()
+ {
+ return $this->_recursiveLevel;
+ }
+ public function setRecursiveLevel($value)
+ {
+ $this->_recursiveLevel=TPropertyValue::ensureInteger($value);
+ }
+ public function getHasChanged()
+ {
+ return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
+ }
+ protected function validateFile($fileName)
+ {
+ return true;
+ }
+ protected function validateDirectory($directory)
+ {
+ return true;
+ }
+ protected function generateTimestamps($directory,$level=0)
+ {
+ if(($dir=opendir($directory))===false)
+ throw new TIOException('directorycachedependency_directory_invalid',$directory);
+ $timestamps=array();
+ while(($file=readdir($dir))!==false)
+ {
+ $path=$directory.DIRECTORY_SEPARATOR.$file;
+ if($file==='.' || $file==='..')
+ continue;
+ else if(is_dir($path))
+ {
+ if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
+ $timestamps=array_merge($this->generateTimestamps($path,$level+1));
+ }
+ else if($this->validateFile($path))
+ $timestamps[$path]=filemtime($path);
+ }
+ closedir($dir);
+ return $timestamps;
+ }
+}
+class TGlobalStateCacheDependency extends TCacheDependency
+{
+ private $_stateName;
+ private $_stateValue;
+ public function __construct($name)
+ {
+ $this->setStateName($name);
+ }
+ public function getStateName()
+ {
+ return $this->_stateName;
+ }
+ public function setStateName($value)
+ {
+ $this->_stateName=$value;
+ $this->_stateValue=Prado::getApplication()->getGlobalState($value);
+ }
+ public function getHasChanged()
+ {
+ return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
+ }
+}
+class TChainedCacheDependency extends TCacheDependency
+{
+ private $_dependencies=null;
+ public function getDependencies()
+ {
+ if($this->_dependencies===null)
+ $this->_dependencies=new TCacheDependencyList;
+ return $this->_dependencies;
+ }
+ public function getHasChanged()
+ {
+ if($this->_dependencies!==null)
+ {
+ foreach($this->_dependencies as $dependency)
+ if($dependency->getHasChanged())
+ return true;
+ }
+ return false;
+ }
+}
+class TApplicationStateCacheDependency extends TCacheDependency
+{
+ public function getHasChanged()
+ {
+ return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
+ }
+}
+class TCacheDependencyList extends TList
+{
+ public function insertAt($index,$item)
+ {
+ if($item instanceof ICacheDependency)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
+ }
+}
+class TTextWriter extends TComponent implements ITextWriter
+{
+ private $_str='';
+ public function flush()
+ {
+ $str=$this->_str;
+ $this->_str='';
+ return $str;
+ }
+ public function write($str)
+ {
+ $this->_str.=$str;
+ }
+ public function writeLine($str='')
+ {
+ $this->write($str."\n");
+ }
+}
+class TPriorityList extends TList
+{
+ private $_d=array();
+ private $_o=false;
+ private $_fd=null;
+ private $_c=0;
+ private $_dp=10;
+ private $_p=8;
+ public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
+ {
+ parent::__construct();
+ if($data!==null)
+ $this->copyFrom($data);
+ $this->setReadOnly($readOnly);
+ $this->setPrecision($precision);
+ $this->setDefaultPriority($defaultPriority);
+ }
+ public function count()
+ {
+ return $this->getCount();
+ }
+ public function getCount()
+ {
+ return $this->_c;
+ }
+ public function getPriorityCount($priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ if(!isset($this->_d[$priority]) || !is_array($this->_d[$priority]))
+ return false;
+ return count($this->_d[$priority]);
+ }
+ public function getDefaultPriority()
+ {
+ return $this->_dp;
+ }
+ protected function setDefaultPriority($value)
+ {
+ $this->_dp=(string)round(TPropertyValue::ensureFloat($value),$this->_p);
+ }
+ public function getPrecision()
+ {
+ return $this->_p;
+ }
+ protected function setPrecision($value)
+ {
+ $this->_p=TPropertyValue::ensureInteger($value);
+ }
+ public function getIterator()
+ {
+ return new ArrayIterator($this->flattenPriorities());
+ }
+ public function getPriorities()
+ {
+ $this->sortPriorities();
+ return array_keys($this->_d);
+ }
+ protected function sortPriorities() {
+ if(!$this->_o) {
+ ksort($this->_d,SORT_NUMERIC);
+ $this->_o=true;
+ }
+ }
+ protected function flattenPriorities() {
+ if(is_array($this->_fd))
+ return $this->_fd;
+ $this->sortPriorities();
+ $this->_fd=array();
+ foreach($this->_d as $priority => $itemsatpriority)
+ $this->_fd=array_merge($this->_fd,$itemsatpriority);
+ return $this->_fd;
+ }
+ public function itemAt($index)
+ {
+ if($index>=0&&$index<$this->getCount()) {
+ $arr=$this->flattenPriorities();
+ return $arr[$index];
+ } else
+ throw new TInvalidDataValueException('list_index_invalid',$index);
+ }
+ public function itemsAtPriority($priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ return isset($this->_d[$priority])?$this->_d[$priority]:null;
+ }
+ public function itemAtIndexInPriority($index,$priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
+ return !isset($this->_d[$priority])?false:(
+ isset($this->_d[$priority][$index])?$this->_d[$priority][$index]:false
+ );
+ }
+ public function add($item,$priority=null)
+ {
+ if($this->getReadOnly())
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ return $this->insertAtIndexInPriority($item,false,$priority,true);
+ }
+ public function insertAt($index,$item)
+ {
+ if($this->getReadOnly())
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ if(($priority=$this->priorityAt($index,true))!==false)
+ $this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
+ else
+ throw new TInvalidDataValueException('list_index_invalid',$index);
+ }
+ public function insertAtIndexInPriority($item,$index=false,$priority=null,$preserveCache=false)
+ {
+ if($this->getReadOnly())
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
+ if($preserveCache) {
+ $this->sortPriorities();
+ $cc=0;
+ foreach($this->_d as $prioritykey=>$items)
+ if($prioritykey>=$priority)
+ break;
+ else
+ $cc+=count($items);
+ if($index===false&&isset($this->_d[$priority])) {
+ $c=count($this->_d[$priority]);
+ $c+=$cc;
+ $this->_d[$priority][]=$item;
+ } else if(isset($this->_d[$priority])) {
+ $c=$index+$cc;
+ array_splice($this->_d[$priority],$index,0,array($item));
+ } else {
+ $c = $cc;
+ $this->_o = false;
+ $this->_d[$priority]=array($item);
+ }
+ if($this->_fd&&is_array($this->_fd)) array_splice($this->_fd,$c,0,array($item));
+ } else {
+ $c=null;
+ if($index===false&&isset($this->_d[$priority])) {
+ $cc=count($this->_d[$priority]);
+ $this->_d[$priority][]=$item;
+ } else if(isset($this->_d[$priority])) {
+ $cc=$index;
+ array_splice($this->_d[$priority],$index,0,array($item));
+ } else {
+ $cc=0;
+ $this->_o=false;
+ $this->_d[$priority]=array($item);
+ }
+ if($this->_fd&&is_array($this->_fd)&&count($this->_d)==1)
+ array_splice($this->_fd,$cc,0,array($item));
+ else
+ $this->_fd=null;
+ }
+ $this->_c++;
+ return $c;
+ }
+ public function remove($item,$priority=false)
+ {
+ if($this->getReadOnly())
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ if(($p=$this->priorityOf($item,true))!==false)
+ {
+ if($priority!==false) {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ if($p[0]!=$priority)
+ throw new TInvalidDataValueException('list_item_inexistent');
+ }
+ $this->removeAtIndexInPriority($p[1],$p[0]);
+ return $p[2];
+ }
+ else
+ throw new TInvalidDataValueException('list_item_inexistent');
+ }
+ public function removeAt($index)
+ {
+ if($this->getReadOnly())
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ if(($priority=$this->priorityAt($index, true))!==false)
+ return $this->removeAtIndexInPriority($priority[1],$priority[0]);
+ throw new TInvalidDataValueException('list_index_invalid',$index);
+ }
+ public function removeAtIndexInPriority($index, $priority=null)
+ {
+ if($this->getReadOnly())
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ if(!isset($this->_d[$priority])||$index<0||$index>=count($this->_d[$priority]))
+ throw new TInvalidDataValueException('list_item_inexistent');
+ $value=array_splice($this->_d[$priority],$index,1);
+ $value=$value[0];
+ if(!count($this->_d[$priority]))
+ unset($this->_d[$priority]);
+ $this->_c--;
+ $this->_fd=null;
+ return $value;
+ }
+ public function clear()
+ {
+ if($this->getReadOnly())
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ $d=array_reverse($this->_d,true);
+ foreach($this->_d as $priority=>$items) {
+ for($index=count($items)-1;$index>=0;$index--)
+ $this->removeAtIndexInPriority($index,$priority);
+ unset($this->_d[$priority]);
+ }
+ }
+ public function contains($item)
+ {
+ return $this->indexOf($item)>=0;
+ }
+ public function indexOf($item)
+ {
+ if(($index=array_search($item,$this->flattenPriorities(),true))===false)
+ return -1;
+ else
+ return $index;
+ }
+ public function priorityOf($item,$withindex = false)
+ {
+ $this->sortPriorities();
+ $absindex = 0;
+ foreach($this->_d as $priority=>$items) {
+ if(($index=array_search($item,$items,true))!==false) {
+ $absindex+=$index;
+ return $withindex?array($priority,$index,$absindex,
+ 'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
+ } else
+ $absindex+=count($items);
+ }
+ return false;
+ }
+ public function priorityAt($index,$withindex = false)
+ {
+ if($index<0||$index>=$this->getCount())
+ throw new TInvalidDataValueException('list_index_invalid',$index);
+ $absindex=$index;
+ $this->sortPriorities();
+ foreach($this->_d as $priority=>$items) {
+ if($index>=($c=count($items)))
+ $index-=$c;
+ else
+ return $withindex?array($priority,$index,$absindex,
+ 'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
+ }
+ return false;
+ }
+ public function insertBefore($indexitem, $item)
+ {
+ if($this->getReadOnly())
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ if(($priority=$this->priorityOf($indexitem,true))===false)
+ throw new TInvalidDataValueException('list_item_inexistent');
+ $this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
+ return $priority[2];
+ }
+ public function insertAfter($indexitem, $item)
+ {
+ if($this->getReadOnly())
+ throw new TInvalidOperationException('list_readonly',get_class($this));
+ if(($priority=$this->priorityOf($indexitem,true))===false)
+ throw new TInvalidDataValueException('list_item_inexistent');
+ $this->insertAtIndexInPriority($item,$priority[1]+1,$priority[0]);
+ return $priority[2]+1;
+ }
+ public function toArray()
+ {
+ return $this->flattenPriorities();
+ }
+ public function toPriorityArray()
+ {
+ $this->sortPriorities();
+ return $this->_d;
+ }
+ public function toArrayBelowPriority($priority,$inclusive=false)
+ {
+ $this->sortPriorities();
+ $items=array();
+ foreach($this->_d as $itemspriority=>$itemsatpriority)
+ {
+ if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
+ break;
+ $items=array_merge($items,$itemsatpriority);
+ }
+ return $items;
+ }
+ public function toArrayAbovePriority($priority,$inclusive=true)
+ {
+ $this->sortPriorities();
+ $items=array();
+ foreach($this->_d as $itemspriority=>$itemsatpriority)
+ {
+ if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
+ continue;
+ $items=array_merge($items,$itemsatpriority);
+ }
+ return $items;
+ }
+ public function copyFrom($data)
+ {
+ if($data instanceof TPriorityList)
+ {
+ if($this->getCount()>0)
+ $this->clear();
+ foreach($data->getPriorities() as $priority)
+ {
+ foreach($data->itemsAtPriority($priority) as $index=>$item)
+ $this->insertAtIndexInPriority($item,$index,$priority);
+ }
+ } else if(is_array($data)||$data instanceof Traversable) {
+ if($this->getCount()>0)
+ $this->clear();
+ foreach($data as $key=>$item)
+ $this->add($item);
+ } else if($data!==null)
+ throw new TInvalidDataTypeException('map_data_not_iterable');
+ }
+ public function mergeWith($data)
+ {
+ if($data instanceof TPriorityList)
+ {
+ foreach($data->getPriorities() as $priority)
+ {
+ foreach($data->itemsAtPriority($priority) as $index=>$item)
+ $this->insertAtIndexInPriority($item,false,$priority);
+ }
+ }
+ else if(is_array($data)||$data instanceof Traversable)
+ {
+ foreach($data as $priority=>$item)
+ $this->add($item);
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('map_data_not_iterable');
+ }
+ public function offsetExists($offset)
+ {
+ return ($offset>=0&&$offset<$this->getCount());
+ }
+ public function offsetGet($offset)
+ {
+ return $this->itemAt($offset);
+ }
+ public function offsetSet($offset,$item)
+ {
+ if($offset===null)
+ return $this->add($item);
+ if($offset===$this->getCount()) {
+ $priority=$this->priorityAt($offset-1,true);
+ $priority[1]++;
+ } else {
+ $priority=$this->priorityAt($offset,true);
+ $this->removeAtIndexInPriority($priority[1],$priority[0]);
+ }
+ $this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
+ }
+ public function offsetUnset($offset)
+ {
+ $this->removeAt($offset);
+ }
+}
+class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable
+{
+ private $_d=array();
+ private $_r=false;
+ public function __construct($data=null,$readOnly=false)
+ {
+ if($data!==null)
+ $this->copyFrom($data);
+ $this->setReadOnly($readOnly);
+ }
+ public function getReadOnly()
+ {
+ return $this->_r;
+ }
+ protected function setReadOnly($value)
+ {
+ $this->_r=TPropertyValue::ensureBoolean($value);
+ }
+ public function getIterator()
+ {
+ return new ArrayIterator( $this->_d );
+ }
+ public function count()
+ {
+ return $this->getCount();
+ }
+ public function getCount()
+ {
+ return count($this->_d);
+ }
+ public function getKeys()
+ {
+ return array_keys($this->_d);
+ }
+ public function itemAt($key)
+ {
+ return isset($this->_d[$key]) ? $this->_d[$key] : null;
+ }
+ public function add($key,$value)
+ {
+ if(!$this->_r)
+ $this->_d[$key]=$value;
+ else
+ throw new TInvalidOperationException('map_readonly',get_class($this));
+ }
+ public function remove($key)
+ {
+ if(!$this->_r)
+ {
+ if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
+ {
+ $value=$this->_d[$key];
+ unset($this->_d[$key]);
+ return $value;
+ }
+ else
+ return null;
+ }
+ else
+ throw new TInvalidOperationException('map_readonly',get_class($this));
+ }
+ public function clear()
+ {
+ foreach(array_keys($this->_d) as $key)
+ $this->remove($key);
+ }
+ public function contains($key)
+ {
+ return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
+ }
+ public function toArray()
+ {
+ return $this->_d;
+ }
+ public function copyFrom($data)
+ {
+ if(is_array($data) || $data instanceof Traversable)
+ {
+ if($this->getCount()>0)
+ $this->clear();
+ foreach($data as $key=>$value)
+ $this->add($key,$value);
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('map_data_not_iterable');
+ }
+ public function mergeWith($data)
+ {
+ if(is_array($data) || $data instanceof Traversable)
+ {
+ foreach($data as $key=>$value)
+ $this->add($key,$value);
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('map_data_not_iterable');
+ }
+ public function offsetExists($offset)
+ {
+ return $this->contains($offset);
+ }
+ public function offsetGet($offset)
+ {
+ return $this->itemAt($offset);
+ }
+ public function offsetSet($offset,$item)
+ {
+ $this->add($offset,$item);
+ }
+ public function offsetUnset($offset)
+ {
+ $this->remove($offset);
+ }
+}
+class TMapIterator implements Iterator
+{
+ private $_d;
+ private $_keys;
+ private $_key;
+ public function __construct(&$data)
+ {
+ $this->_d=&$data;
+ $this->_keys=array_keys($data);
+ }
+ public function rewind()
+ {
+ $this->_key=reset($this->_keys);
+ }
+ public function key()
+ {
+ return $this->_key;
+ }
+ public function current()
+ {
+ return $this->_d[$this->_key];
+ }
+ public function next()
+ {
+ $this->_key=next($this->_keys);
+ }
+ public function valid()
+ {
+ return $this->_key!==false;
+ }
+}
+class TPriorityMap extends TMap
+{
+ private $_d=array();
+ private $_r=false;
+ private $_o=false;
+ private $_fd=null;
+ private $_c=0;
+ private $_dp=10;
+ private $_p=8;
+ public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
+ {
+ if($data!==null)
+ $this->copyFrom($data);
+ $this->setReadOnly($readOnly);
+ $this->setPrecision($precision);
+ $this->setDefaultPriority($defaultPriority);
+ }
+ public function getReadOnly()
+ {
+ return $this->_r;
+ }
+ protected function setReadOnly($value)
+ {
+ $this->_r=TPropertyValue::ensureBoolean($value);
+ }
+ public function getDefaultPriority()
+ {
+ return $this->_dp;
+ }
+ protected function setDefaultPriority($value)
+ {
+ $this->_dp = (string)round(TPropertyValue::ensureFloat($value), $this->_p);
+ }
+ public function getPrecision()
+ {
+ return $this->_p;
+ }
+ protected function setPrecision($value)
+ {
+ $this->_p=TPropertyValue::ensureInteger($value);
+ }
+ public function getIterator()
+ {
+ return new ArrayIterator($this->flattenPriorities());
+ }
+ protected function sortPriorities() {
+ if(!$this->_o) {
+ ksort($this->_d, SORT_NUMERIC);
+ $this->_o=true;
+ }
+ }
+ protected function flattenPriorities() {
+ if(is_array($this->_fd))
+ return $this->_fd;
+ $this->sortPriorities();
+ $this->_fd = array();
+ foreach($this->_d as $priority => $itemsatpriority)
+ $this->_fd = array_merge($this->_fd, $itemsatpriority);
+ return $this->_fd;
+ }
+ public function count()
+ {
+ return $this->getCount();
+ }
+ public function getCount()
+ {
+ return $this->_c;
+ }
+ public function getPriorityCount($priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ if(!isset($this->_d[$priority])||!is_array($this->_d[$priority]))
+ return false;
+ return count($this->_d[$priority]);
+ }
+ public function getPriorities()
+ {
+ $this->sortPriorities();
+ return array_keys($this->_d);
+ }
+ public function getKeys()
+ {
+ return array_keys($this->flattenPriorities());
+ }
+ public function itemAt($key,$priority=false)
+ {
+ if($priority===false){
+ $map=$this->flattenPriorities();
+ return isset($map[$key])?$map[$key]:null;
+ } else {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ return (isset($this->_d[$priority])&&isset($this->_d[$priority][$key]))?$this->_d[$priority][$key]:null;
+ }
+ }
+ public function setPriorityAt($key,$priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ $oldpriority=$this->priorityAt($key);
+ if($oldpriority!==false&&$oldpriority!=$priority) {
+ $value=$this->remove($key,$oldpriority);
+ $this->add($key,$value,$priority);
+ }
+ return $oldpriority;
+ }
+ public function itemsAtPriority($priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ return isset($this->_d[$priority])?$this->_d[$priority]:null;
+ }
+ public function priorityOf($item)
+ {
+ $this->sortPriorities();
+ foreach($this->_d as $priority=>$items)
+ if(($index=array_search($item,$items,true))!==false)
+ return $priority;
+ return false;
+ }
+ public function priorityAt($key)
+ {
+ $this->sortPriorities();
+ foreach($this->_d as $priority=>$items)
+ if(array_key_exists($key,$items))
+ return $priority;
+ return false;
+ }
+ public function add($key,$value,$priority=null)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ if(!$this->_r)
+ {
+ foreach($this->_d as $innerpriority=>$items)
+ if(array_key_exists($key,$items))
+ {
+ unset($this->_d[$innerpriority][$key]);
+ $this->_c--;
+ if(count($this->_d[$innerpriority])===0)
+ unset($this->_d[$innerpriority]);
+ }
+ if(!isset($this->_d[$priority])) {
+ $this->_d[$priority]=array($key=>$value);
+ $this->_o=false;
+ }
+ else
+ $this->_d[$priority][$key]=$value;
+ $this->_c++;
+ $this->_fd=null;
+ }
+ else
+ throw new TInvalidOperationException('map_readonly',get_class($this));
+ return $priority;
+ }
+ public function remove($key,$priority=false)
+ {
+ if(!$this->_r)
+ {
+ if($priority===null)
+ $priority=$this->getDefaultPriority();
+ if($priority===false)
+ {
+ $this->sortPriorities();
+ foreach($this->_d as $priority=>$items)
+ if(array_key_exists($key,$items))
+ {
+ $value=$this->_d[$priority][$key];
+ unset($this->_d[$priority][$key]);
+ $this->_c--;
+ if(count($this->_d[$priority])===0)
+ {
+ unset($this->_d[$priority]);
+ $this->_o=false;
+ }
+ $this->_fd=null;
+ return $value;
+ }
+ return null;
+ }
+ else
+ {
+ $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
+ if(isset($this->_d[$priority])&&(isset($this->_d[$priority][$key])||array_key_exists($key,$this->_d[$priority])))
+ {
+ $value=$this->_d[$priority][$key];
+ unset($this->_d[$priority][$key]);
+ $this->_c--;
+ if(count($this->_d[$priority])===0) {
+ unset($this->_d[$priority]);
+ $this->_o=false;
+ }
+ $this->_fd=null;
+ return $value;
+ }
+ else
+ return null;
+ }
+ }
+ else
+ throw new TInvalidOperationException('map_readonly',get_class($this));
+ }
+ public function clear()
+ {
+ foreach($this->_d as $priority=>$items)
+ foreach(array_keys($items) as $key)
+ $this->remove($key);
+ }
+ public function contains($key)
+ {
+ $map=$this->flattenPriorities();
+ return isset($map[$key])||array_key_exists($key,$map);
+ }
+ public function toArray()
+ {
+ return $this->flattenPriorities();
+ }
+ public function toArrayBelowPriority($priority,$inclusive=false)
+ {
+ $this->sortPriorities();
+ $items=array();
+ foreach($this->_d as $itemspriority=>$itemsatpriority)
+ {
+ if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
+ break;
+ $items=array_merge($items,$itemsatpriority);
+ }
+ return $items;
+ }
+ public function toArrayAbovePriority($priority,$inclusive=true)
+ {
+ $this->sortPriorities();
+ $items=array();
+ foreach($this->_d as $itemspriority=>$itemsatpriority)
+ {
+ if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
+ continue;
+ $items=array_merge($items,$itemsatpriority);
+ }
+ return $items;
+ }
+ public function copyFrom($data)
+ {
+ if($data instanceof TPriorityMap)
+ {
+ if($this->getCount()>0)
+ $this->clear();
+ foreach($data->getPriorities() as $priority) {
+ foreach($data->itemsAtPriority($priority) as $key => $value) {
+ $this->add($key,$value,$priority);
+ }
+ }
+ }
+ else if(is_array($data)||$data instanceof Traversable)
+ {
+ if($this->getCount()>0)
+ $this->clear();
+ foreach($data as $key=>$value)
+ $this->add($key,$value);
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('map_data_not_iterable');
+ }
+ public function mergeWith($data)
+ {
+ if($data instanceof TPriorityMap)
+ {
+ foreach($data->getPriorities() as $priority)
+ {
+ foreach($data->itemsAtPriority($priority) as $key => $value)
+ $this->add($key,$value,$priority);
+ }
+ }
+ else if(is_array($data)||$data instanceof Traversable)
+ {
+ foreach($data as $key=>$value)
+ $this->add($key,$value);
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('map_data_not_iterable');
+ }
+ public function offsetExists($offset)
+ {
+ return $this->contains($offset);
+ }
+ public function offsetGet($offset)
+ {
+ return $this->itemAt($offset);
+ }
+ public function offsetSet($offset,$item)
+ {
+ $this->add($offset,$item);
+ }
+ public function offsetUnset($offset)
+ {
+ $this->remove($offset);
+ }
+}
+class TStack extends TComponent implements IteratorAggregate,Countable
+{
+ private $_d=array();
+ private $_c=0;
+ public function __construct($data=null)
+ {
+ if($data!==null)
+ $this->copyFrom($data);
+ }
+ public function toArray()
+ {
+ return $this->_d;
+ }
+ public function copyFrom($data)
+ {
+ if(is_array($data) || ($data instanceof Traversable))
+ {
+ $this->clear();
+ foreach($data as $item)
+ {
+ $this->_d[]=$item;
+ ++$this->_c;
+ }
+ }
+ else if($data!==null)
+ throw new TInvalidDataTypeException('stack_data_not_iterable');
+ }
+ public function clear()
+ {
+ $this->_c=0;
+ $this->_d=array();
+ }
+ public function contains($item)
+ {
+ return array_search($item,$this->_d,true)!==false;
+ }
+ public function peek()
+ {
+ if($this->_c===0)
+ throw new TInvalidOperationException('stack_empty');
+ else
+ return $this->_d[$this->_c-1];
+ }
+ public function pop()
+ {
+ if($this->_c===0)
+ throw new TInvalidOperationException('stack_empty');
+ else
+ {
+ --$this->_c;
+ return array_pop($this->_d);
+ }
+ }
+ public function push($item)
+ {
+ ++$this->_c;
+ $this->_d[] = $item;
+ }
+ public function getIterator()
+ {
+ return new ArrayIterator( $this->_d );
+ }
+ public function getCount()
+ {
+ return $this->_c;
+ }
+ public function count()
+ {
+ return $this->getCount();
+ }
+}
+class TStackIterator implements Iterator
+{
+ private $_d;
+ private $_i;
+ private $_c;
+ public function __construct(&$data)
+ {
+ $this->_d=&$data;
+ $this->_i=0;
+ $this->_c=count($this->_d);
+ }
+ public function rewind()
+ {
+ $this->_i=0;
+ }
+ public function key()
+ {
+ return $this->_i;
+ }
+ public function current()
+ {
+ return $this->_d[$this->_i];
+ }
+ public function next()
+ {
+ $this->_i++;
+ }
+ public function valid()
+ {
+ return $this->_i<$this->_c;
+ }
+}
+class TXmlElement extends TComponent
+{
+ private $_parent=null;
+ private $_tagName='unknown';
+ private $_value='';
+ private $_elements=null;
+ private $_attributes=null;
+ public function __construct($tagName)
+ {
+ $this->setTagName($tagName);
+ }
+ public function getParent()
+ {
+ return $this->_parent;
+ }
+ public function setParent($parent)
+ {
+ $this->_parent=$parent;
+ }
+ public function getTagName()
+ {
+ return $this->_tagName;
+ }
+ public function setTagName($tagName)
+ {
+ $this->_tagName=$tagName;
+ }
+ public function getValue()
+ {
+ return $this->_value;
+ }
+ public function setValue($value)
+ {
+ $this->_value=TPropertyValue::ensureString($value);
+ }
+ public function getHasElement()
+ {
+ return $this->_elements!==null && $this->_elements->getCount()>0;
+ }
+ public function getHasAttribute()
+ {
+ return $this->_attributes!==null && $this->_attributes->getCount()>0;
+ }
+ public function getAttribute($name)
+ {
+ if($this->_attributes!==null)
+ return $this->_attributes->itemAt($name);
+ else
+ return null;
+ }
+ public function setAttribute($name,$value)
+ {
+ $this->getAttributes()->add($name,TPropertyValue::ensureString($value));
+ }
+ public function getElements()
+ {
+ if(!$this->_elements)
+ $this->_elements=new TXmlElementList($this);
+ return $this->_elements;
+ }
+ public function getAttributes()
+ {
+ if(!$this->_attributes)
+ $this->_attributes=new TMap;
+ return $this->_attributes;
+ }
+ public function getElementByTagName($tagName)
+ {
+ if($this->_elements)
+ {
+ foreach($this->_elements as $element)
+ if($element->_tagName===$tagName)
+ return $element;
+ }
+ return null;
+ }
+ public function getElementsByTagName($tagName)
+ {
+ $list=new TList;
+ if($this->_elements)
+ {
+ foreach($this->_elements as $element)
+ if($element->_tagName===$tagName)
+ $list->add($element);
+ }
+ return $list;
+ }
+ public function toString($indent=0)
+ {
+ $attr='';
+ if($this->_attributes!==null)
+ {
+ foreach($this->_attributes as $name=>$value)
+ {
+ $value=$this->xmlEncode($value);
+ $attr.=" $name=\"$value\"";
+ }
+ }
+ $prefix=str_repeat(' ',$indent*4);
+ if($this->getHasElement())
+ {
+ $str=$prefix."<{$this->_tagName}$attr>\n";
+ foreach($this->getElements() as $element)
+ $str.=$element->toString($indent+1)."\n";
+ $str.=$prefix."</{$this->_tagName}>";
+ return $str;
+ }
+ else if(($value=$this->getValue())!=='')
+ {
+ $value=$this->xmlEncode($value);
+ return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>";
+ }
+ else
+ return $prefix."<{$this->_tagName}$attr />";
+ }
+ public function __toString()
+ {
+ return $this->toString();
+ }
+ private function xmlEncode($str)
+ {
+ return strtr($str,array(
+ '>'=>'&gt;',
+ '<'=>'&lt;',
+ '&'=>'&amp;',
+ '"'=>'&quot;',
+ "\r"=>'&#xD;',
+ "\t"=>'&#x9;',
+ "\n"=>'&#xA;'));
+ }
+}
+class TXmlDocument extends TXmlElement
+{
+ private $_version;
+ private $_encoding;
+ public function __construct($version='1.0',$encoding='')
+ {
+ parent::__construct('');
+ $this->setVersion($version);
+ $this->setEncoding($encoding);
+ }
+ public function getVersion()
+ {
+ return $this->_version;
+ }
+ public function setVersion($version)
+ {
+ $this->_version=$version;
+ }
+ public function getEncoding()
+ {
+ return $this->_encoding;
+ }
+ public function setEncoding($encoding)
+ {
+ $this->_encoding=$encoding;
+ }
+ public function loadFromFile($file)
+ {
+ if(($str=@file_get_contents($file))!==false)
+ return $this->loadFromString($str);
+ else
+ throw new TIOException('xmldocument_file_read_failed',$file);
+ }
+ public function loadFromString($string)
+ {
+ $doc=new DOMDocument();
+ if($doc->loadXML($string)===false)
+ return false;
+ $this->setEncoding($doc->encoding);
+ $this->setVersion($doc->version);
+ $element=$doc->documentElement;
+ $this->setTagName($element->tagName);
+ $this->setValue($element->nodeValue);
+ $elements=$this->getElements();
+ $attributes=$this->getAttributes();
+ $elements->clear();
+ $attributes->clear();
+ static $bSimpleXml;
+ if($bSimpleXml === null)
+ $bSimpleXml = (boolean)function_exists('simplexml_load_string');
+ if($bSimpleXml)
+ {
+ $simpleDoc = simplexml_load_string($string);
+ $docNamespaces = $simpleDoc->getDocNamespaces(false);
+ $simpleDoc = null;
+ foreach($docNamespaces as $prefix => $uri)
+ {
+ if($prefix === '')
+ $attributes->add('xmlns', $uri);
+ else
+ $attributes->add('xmlns:'.$prefix, $uri);
+ }
+ }
+ foreach($element->attributes as $name=>$attr)
+ $attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value);
+ foreach($element->childNodes as $child)
+ {
+ if($child instanceof DOMElement)
+ $elements->add($this->buildElement($child));
+ }
+ return true;
+ }
+ public function saveToFile($file)
+ {
+ if(($fw=fopen($file,'w'))!==false)
+ {
+ fwrite($fw,$this->saveToString());
+ fclose($fw);
+ }
+ else
+ throw new TIOException('xmldocument_file_write_failed',$file);
+ }
+ public function saveToString()
+ {
+ $version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
+ $encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
+ return "<?xml{$version}{$encoding}?>\n".$this->toString(0);
+ }
+ public function __toString()
+ {
+ return $this->saveToString();
+ }
+ protected function buildElement($node)
+ {
+ $element=new TXmlElement($node->tagName);
+ $element->setValue($node->nodeValue);
+ foreach($node->attributes as $name=>$attr)
+ $element->getAttributes()->add(($attr->prefix === '' ? '' : $attr->prefix . ':') . $name,$attr->value);
+ foreach($node->childNodes as $child)
+ {
+ if($child instanceof DOMElement)
+ $element->getElements()->add($this->buildElement($child));
+ }
+ return $element;
+ }
+}
+class TXmlElementList extends TList
+{
+ private $_o;
+ public function __construct(TXmlElement $owner)
+ {
+ $this->_o=$owner;
+ }
+ protected function getOwner()
+ {
+ return $this->_o;
+ }
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TXmlElement)
+ {
+ parent::insertAt($index,$item);
+ if($item->getParent()!==null)
+ $item->getParent()->getElements()->remove($item);
+ $item->setParent($this->_o);
+ }
+ else
+ throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
+ }
+ public function removeAt($index)
+ {
+ $item=parent::removeAt($index);
+ if($item instanceof TXmlElement)
+ $item->setParent(null);
+ return $item;
+ }
+}
+class TAuthorizationRule extends TComponent
+{
+ private $_action;
+ private $_users;
+ private $_roles;
+ private $_verb;
+ private $_ipRules;
+ private $_everyone;
+ private $_guest;
+ private $_authenticated;
+ public function __construct($action,$users,$roles,$verb='',$ipRules='')
+ {
+ $action=strtolower(trim($action));
+ if($action==='allow' || $action==='deny')
+ $this->_action=$action;
+ else
+ throw new TInvalidDataValueException('authorizationrule_action_invalid',$action);
+ $this->_users=array();
+ $this->_roles=array();
+ $this->_ipRules=array();
+ $this->_everyone=false;
+ $this->_guest=false;
+ $this->_authenticated=false;
+ if(trim($users)==='')
+ $users='*';
+ foreach(explode(',',$users) as $user)
+ {
+ if(($user=trim(strtolower($user)))!=='')
+ {
+ if($user==='*')
+ {
+ $this->_everyone=true;
+ break;
+ }
+ else if($user==='?')
+ $this->_guest=true;
+ else if($user==='@')
+ $this->_authenticated=true;
+ else
+ $this->_users[]=$user;
+ }
+ }
+ if(trim($roles)==='')
+ $roles='*';
+ foreach(explode(',',$roles) as $role)
+ {
+ if(($role=trim(strtolower($role)))!=='')
+ $this->_roles[]=$role;
+ }
+ if(($verb=trim(strtolower($verb)))==='')
+ $verb='*';
+ if($verb==='*' || $verb==='get' || $verb==='post')
+ $this->_verb=$verb;
+ else
+ throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb);
+ if(trim($ipRules)==='')
+ $ipRules='*';
+ foreach(explode(',',$ipRules) as $ipRule)
+ {
+ if(($ipRule=trim($ipRule))!=='')
+ $this->_ipRules[]=$ipRule;
+ }
+ }
+ public function getAction()
+ {
+ return $this->_action;
+ }
+ public function getUsers()
+ {
+ return $this->_users;
+ }
+ public function getRoles()
+ {
+ return $this->_roles;
+ }
+ public function getVerb()
+ {
+ return $this->_verb;
+ }
+ public function getIPRules()
+ {
+ return $this->_ipRules;
+ }
+ public function getGuestApplied()
+ {
+ return $this->_guest || $this->_everyone;
+ }
+ public function getEveryoneApplied()
+ {
+ return $this->_everyone;
+ }
+ public function getAuthenticatedApplied()
+ {
+ return $this->_authenticated || $this->_everyone;
+ }
+ public function isUserAllowed(IUser $user,$verb,$ip)
+ {
+ if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user))
+ return ($this->_action==='allow')?1:-1;
+ else
+ return 0;
+ }
+ private function isIpMatched($ip)
+ {
+ if(empty($this->_ipRules))
+ return 1;
+ foreach($this->_ipRules as $rule)
+ {
+ if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0))
+ return 1;
+ }
+ return 0;
+ }
+ private function isUserMatched($user)
+ {
+ return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users));
+ }
+ private function isRoleMatched($user)
+ {
+ foreach($this->_roles as $role)
+ {
+ if($role==='*' || $user->isInRole($role))
+ return true;
+ }
+ return false;
+ }
+ private function isVerbMatched($verb)
+ {
+ return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0);
+ }
+}
+class TAuthorizationRuleCollection extends TList
+{
+ public function isUserAllowed($user,$verb,$ip)
+ {
+ if($user instanceof IUser)
+ {
+ $verb=strtolower(trim($verb));
+ foreach($this as $rule)
+ {
+ if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0)
+ return ($decision>0);
+ }
+ return true;
+ }
+ else
+ return false;
+ }
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TAuthorizationRule)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required');
+ }
+}
+class TSecurityManager extends TModule
+{
+ const STATE_VALIDATION_KEY = 'prado:securitymanager:validationkey';
+ const STATE_ENCRYPTION_KEY = 'prado:securitymanager:encryptionkey';
+ private $_validationKey = null;
+ private $_encryptionKey = null;
+ private $_hashAlgorithm = 'sha1';
+ private $_cryptAlgorithm = 'rijndael-256';
+ private $_mbstring;
+ public function init($config)
+ {
+ $this->_mbstring=extension_loaded('mbstring');
+ $this->getApplication()->setSecurityManager($this);
+ }
+ protected function generateRandomKey()
+ {
+ return sprintf('%08x%08x%08x%08x',mt_rand(),mt_rand(),mt_rand(),mt_rand());
+ }
+ public function getValidationKey()
+ {
+ if(null === $this->_validationKey) {
+ if(null === ($this->_validationKey = $this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))) {
+ $this->_validationKey = $this->generateRandomKey();
+ $this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY, $this->_validationKey, null, true);
+ }
+ }
+ return $this->_validationKey;
+ }
+ public function setValidationKey($value)
+ {
+ if('' === $value)
+ throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
+ $this->_validationKey = $value;
+ }
+ public function getEncryptionKey()
+ {
+ if(null === $this->_encryptionKey) {
+ if(null === ($this->_encryptionKey = $this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))) {
+ $this->_encryptionKey = $this->generateRandomKey();
+ $this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY, $this->_encryptionKey, null, true);
+ }
+ }
+ return $this->_encryptionKey;
+ }
+ public function setEncryptionKey($value)
+ {
+ if('' === $value)
+ throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
+ $this->_encryptionKey = $value;
+ }
+ public function getValidation()
+ {
+ return $this->_hashAlgorithm;
+ }
+ public function getHashAlgorithm()
+ {
+ return $this->_hashAlgorithm;
+ }
+ public function setValidation($value)
+ {
+ $this->_hashAlgorithm = TPropertyValue::ensureEnum($value, 'TSecurityManagerValidationMode');
+ }
+ public function setHashAlgorithm($value)
+ {
+ $this->_hashAlgorithm = TPropertyValue::ensureString($value);
+ }
+ public function getEncryption()
+ {
+ if(is_string($this->_cryptAlgorithm))
+ return $this->_cryptAlgorithm;
+ return "3DES";
+ }
+ public function setEncryption($value)
+ {
+ $this->_cryptAlgorithm = $value;
+ }
+ public function getCryptAlgorithm()
+ {
+ return $this->_cryptAlgorithm;
+ }
+ public function setCryptAlgorithm($value)
+ {
+ $this->_cryptAlgorithm = $value;
+ }
+ public function encrypt($data)
+ {
+ $module=$this->openCryptModule();
+ $key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
+ srand();
+ $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
+ mcrypt_generic_init($module, $key, $iv);
+ $encrypted = $iv.mcrypt_generic($module, $data);
+ mcrypt_generic_deinit($module);
+ mcrypt_module_close($module);
+ return $encrypted;
+ }
+ public function decrypt($data)
+ {
+ $module=$this->openCryptModule();
+ $key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
+ $ivSize = mcrypt_enc_get_iv_size($module);
+ $iv = $this->substr($data, 0, $ivSize);
+ mcrypt_generic_init($module, $key, $iv);
+ $decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data)));
+ mcrypt_generic_deinit($module);
+ mcrypt_module_close($module);
+ return $decrypted;
+ }
+ protected function openCryptModule()
+ {
+ if(extension_loaded('mcrypt'))
+ {
+ if(is_array($this->_cryptAlgorithm))
+ $module=@call_user_func_array('mcrypt_module_open',$this->_cryptAlgorithm);
+ else
+ $module=@mcrypt_module_open($this->_cryptAlgorithm,'', MCRYPT_MODE_CBC,'');
+ if($module===false)
+ throw new TNotSupportedException('securitymanager_mcryptextension_initfailed');
+ return $module;
+ }
+ else
+ throw new TNotSupportedException('securitymanager_mcryptextension_required');
+ }
+ public function hashData($data)
+ {
+ $hmac = $this->computeHMAC($data);
+ return $hmac.$data;
+ }
+ public function validateData($data)
+ {
+ $len=$this->strlen($this->computeHMAC('test'));
+ if($this->strlen($data) < $len)
+ return false;
+ $hmac = $this->substr($data, 0, $len);
+ $data2=$this->substr($data, $len, $this->strlen($data));
+ return $hmac === $this->computeHMAC($data2) ? $data2 : false;
+ }
+ protected function computeHMAC($data)
+ {
+ $key = $this->getValidationKey();
+ if(function_exists('hash_hmac'))
+ return hash_hmac($this->_hashAlgorithm, $data, $key);
+ if(!strcasecmp($this->_hashAlgorithm,'sha1'))
+ {
+ $pack = 'H40';
+ $func = 'sha1';
+ } else {
+ $pack = 'H32';
+ $func = 'md5';
+ }
+ $key = str_pad($func($key), 64, chr(0));
+ return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
+ }
+ private function strlen($string)
+ {
+ return $this->_mbstring ? mb_strlen($string,'8bit') : strlen($string);
+ }
+ private function substr($string,$start,$length)
+ {
+ return $this->_mbstring ? mb_substr($string,$start,$length,'8bit') : substr($string,$start,$length);
+ }
+}
+class TSecurityManagerValidationMode extends TEnumerable
+{
+ const MD5 = 'MD5';
+ const SHA1 = 'SHA1';
+}
+class THttpUtility
+{
+ private static $_encodeTable=array('<'=>'&lt;','>'=>'&gt;','"'=>'&quot;');
+ private static $_decodeTable=array('&lt;'=>'<','&gt;'=>'>','&quot;'=>'"');
+ private static $_stripTable=array('&lt;'=>'','&gt;'=>'','&quot;'=>'');
+ public static function htmlEncode($s)
+ {
+ return strtr($s,self::$_encodeTable);
+ }
+ public static function htmlDecode($s)
+ {
+ return strtr($s,self::$_decodeTable);
+ }
+ public static function htmlStrip($s)
+ {
+ return strtr($s,self::$_stripTable);
+ }
+}
+class TJavaScript
+{
+ public static function renderScriptFiles($files)
+ {
+ $str='';
+ foreach($files as $file)
+ $str.= self::renderScriptFile($file);
+ return $str;
+ }
+ public static function renderScriptFile($file)
+ {
+ return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
+ }
+ public static function renderScriptBlocks($scripts)
+ {
+ if(count($scripts))
+ return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
+ else
+ return '';
+ }
+ public static function renderScriptBlocksCallback($scripts)
+ {
+ if(count($scripts))
+ return implode("\n",$scripts)."\n";
+ else
+ return '';
+ }
+ public static function renderScriptBlock($script)
+ {
+ return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
+ }
+ public static function quoteString($js)
+ {
+ return self::jsonEncode($js,JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG);
+ }
+ public static function quoteJsLiteral($js)
+ {
+ if($js instanceof TJavaScriptLiteral)
+ return $js;
+ else
+ return new TJavaScriptLiteral($js);
+ }
+ public static function quoteFunction($js)
+ {
+ return self::quoteJsLiteral($js);
+ }
+ public static function isJsLiteral($js)
+ {
+ return ($js instanceof TJavaScriptLiteral);
+ }
+ public static function isFunction($js)
+ {
+ return self::isJsLiteral($js);
+ }
+ public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
+ {
+ if(is_string($value))
+ return self::quoteString($value);
+ else if(is_bool($value))
+ return $value?'true':'false';
+ else if(is_array($value))
+ {
+ $results='';
+ if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
+ {
+ foreach($value as $k=>$v)
+ {
+ if($v!=='' || $encodeEmptyStrings)
+ {
+ if($results!=='')
+ $results.=',';
+ $results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings);
+ }
+ }
+ return '{'.$results.'}';
+ }
+ else
+ {
+ foreach($value as $v)
+ {
+ if($v!=='' || $encodeEmptyStrings)
+ {
+ if($results!=='')
+ $results.=',';
+ $results.=self::encode($v,$toMap, $encodeEmptyStrings);
+ }
+ }
+ return '['.$results.']';
+ }
+ }
+ else if(is_integer($value))
+ return "$value";
+ else if(is_float($value))
+ {
+ switch($value)
+ {
+ case -INF:
+ return 'Number.NEGATIVE_INFINITY';
+ break;
+ case INF:
+ return 'Number.POSITIVE_INFINITY';
+ break;
+ default:
+ $locale=localeConv();
+ if($locale['decimal_point']=='.')
+ return "$value";
+ else
+ return str_replace($locale['decimal_point'], '.', "$value");
+ break;
+ }
+ }
+ else if(is_object($value))
+ if ($value instanceof TJavaScriptLiteral)
+ return $value->toJavaScriptLiteral();
+ else
+ return self::encode(get_object_vars($value),$toMap);
+ else if($value===null)
+ return 'null';
+ else
+ return '';
+ }
+ public static function jsonEncode($value, $options = 0)
+ {
+ if (($g=Prado::getApplication()->getGlobalization(false))!==null &&
+ strtoupper($enc=$g->getCharset())!='UTF-8') {
+ self::convertToUtf8($value, $enc);
+ }
+ $s = @json_encode($value,$options);
+ self::checkJsonError();
+ return $s;
+ }
+ private static function convertToUtf8(&$value, $sourceEncoding) {
+ if(is_string($value))
+ $value=iconv($sourceEncoding, 'UTF-8', $value);
+ else if (is_array($value))
+ {
+ foreach($value as &$element)
+ self::convertToUtf8($element, $sourceEncoding);
+ }
+ }
+ public static function jsonDecode($value, $assoc = false, $depth = 512)
+ {
+ $s= @json_decode($value, $assoc, $depth);
+ self::checkJsonError();
+ return $s;
+ }
+ private static function checkJsonError()
+ {
+ switch ($err = json_last_error())
+ {
+ case JSON_ERROR_NONE:
+ return;
+ break;
+ case JSON_ERROR_DEPTH:
+ $msg = 'Maximum stack depth exceeded';
+ break;
+ case JSON_ERROR_STATE_MISMATCH:
+ $msg = 'Underflow or the modes mismatch';
+ break;
+ case JSON_ERROR_CTRL_CHAR:
+ $msg = 'Unexpected control character found';
+ break;
+ case JSON_ERROR_SYNTAX:
+ $msg = 'Syntax error, malformed JSON';
+ break;
+ case JSON_ERROR_UTF8:
+ $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
+ break;
+ default:
+ $msg = 'Unknown error';
+ break;
+ }
+ throw new Exception("JSON error ($err): $msg");
+ }
+ public static function JSMin($code)
+ {
+ Prado::using('System.Web.Javascripts.JSMin');
+ return JSMin::minify($code);
+ }
+}
+class TUrlManager extends TModule
+{
+ public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
+ {
+ $url=$serviceID.'='.urlencode($serviceParam);
+ $amp=$encodeAmpersand?'&amp;':'&';
+ $request=$this->getRequest();
+ if(is_array($getItems) || $getItems instanceof Traversable)
+ {
+ if($encodeGetItems)
+ {
+ foreach($getItems as $name=>$value)
+ {
+ if(is_array($value))
+ {
+ $name=urlencode($name.'[]');
+ foreach($value as $v)
+ $url.=$amp.$name.'='.urlencode($v);
+ }
+ else
+ $url.=$amp.urlencode($name).'='.urlencode($value);
+ }
+ }
+ else
+ {
+ foreach($getItems as $name=>$value)
+ {
+ if(is_array($value))
+ {
+ foreach($value as $v)
+ $url.=$amp.$name.'[]='.$v;
+ }
+ else
+ $url.=$amp.$name.'='.$value;
+ }
+ }
+ }
+ switch($request->getUrlFormat())
+ {
+ case THttpRequestUrlFormat::Path:
+ return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
+ case THttpRequestUrlFormat::HiddenPath:
+ return rtrim(dirname($request->getApplicationUrl()), '/').'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
+ default:
+ return $request->getApplicationUrl().'?'.$url;
+ }
+ }
+ public function parseUrl()
+ {
+ $request=$this->getRequest();
+ $pathInfo=trim($request->getPathInfo(),'/');
+ if(($request->getUrlFormat()===THttpRequestUrlFormat::Path ||
+ $request->getUrlFormat()===THttpRequestUrlFormat::HiddenPath) &&
+ $pathInfo!=='')
+ {
+ $separator=$request->getUrlParamSeparator();
+ $paths=explode('/',$pathInfo);
+ $getVariables=array();
+ foreach($paths as $path)
+ {
+ if(($path=trim($path))!=='')
+ {
+ if(($pos=strpos($path,$separator))!==false)
+ {
+ $name=substr($path,0,$pos);
+ $value=substr($path,$pos+1);
+ if(($pos=strpos($name,'[]'))!==false)
+ $getVariables[substr($name,0,$pos)][]=$value;
+ else
+ $getVariables[$name]=$value;
+ }
+ else
+ $getVariables[$path]='';
+ }
+ }
+ return $getVariables;
+ }
+ else
+ return array();
+ }
+}
+class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
+{
+ const CGIFIX__PATH_INFO = 1;
+ const CGIFIX__SCRIPT_NAME = 2;
+ private $_urlManager=null;
+ private $_urlManagerID='';
+ private $_separator=',';
+ private $_serviceID=null;
+ private $_serviceParam=null;
+ private $_cookies=null;
+ private $_requestUri;
+ private $_pathInfo;
+ private $_cookieOnly=null;
+ private $_urlFormat=THttpRequestUrlFormat::Get;
+ private $_services;
+ private $_requestResolved=false;
+ private $_enableCookieValidation=false;
+ private $_cgiFix=0;
+ private $_enableCache=false;
+ private $_url=null;
+ private $_id;
+ private $_items=array();
+ public function getID()
+ {
+ return $this->_id;
+ }
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+ public function init($config)
+ {
+ if(php_sapi_name()==='cli')
+ {
+ $_SERVER['REMOTE_ADDR']='127.0.0.1';
+ $_SERVER['REQUEST_METHOD']='GET';
+ $_SERVER['SERVER_NAME']='localhost';
+ $_SERVER['SERVER_PORT']=80;
+ $_SERVER['HTTP_USER_AGENT']='';
+ }
+ if(isset($_SERVER['REQUEST_URI']))
+ $this->_requestUri=$_SERVER['REQUEST_URI'];
+ else $this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
+ if($this->_cgiFix&self::CGIFIX__PATH_INFO && isset($_SERVER['ORIG_PATH_INFO']))
+ $this->_pathInfo=substr($_SERVER['ORIG_PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
+ elseif(isset($_SERVER['PATH_INFO']))
+ $this->_pathInfo=$_SERVER['PATH_INFO'];
+ else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
+ $this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
+ else
+ $this->_pathInfo='';
+ if(get_magic_quotes_gpc())
+ {
+ if(isset($_GET))
+ $_GET=$this->stripSlashes($_GET);
+ if(isset($_POST))
+ $_POST=$this->stripSlashes($_POST);
+ if(isset($_REQUEST))
+ $_REQUEST=$this->stripSlashes($_REQUEST);
+ if(isset($_COOKIE))
+ $_COOKIE=$this->stripSlashes($_COOKIE);
+ }
+ $this->getApplication()->setRequest($this);
+ }
+ public function stripSlashes(&$data)
+ {
+ return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
+ }
+ public function getUrl()
+ {
+ if($this->_url===null)
+ {
+ $secure=$this->getIsSecureConnection();
+ $url=$secure?'https://':'http://';
+ if(empty($_SERVER['HTTP_HOST']))
+ {
+ $url.=$_SERVER['SERVER_NAME'];
+ $port=$_SERVER['SERVER_PORT'];
+ if(($port!=80 && !$secure) || ($port!=443 && $secure))
+ $url.=':'.$port;
+ }
+ else
+ $url.=$_SERVER['HTTP_HOST'];
+ $url.=$this->getRequestUri();
+ $this->_url=new TUri($url);
+ }
+ return $this->_url;
+ }
+ public function setEnableCache($value)
+ {
+ $this->_enableCache = TPropertyValue::ensureBoolean($value);
+ }
+ public function getEnableCache()
+ {
+ return $this->_enableCache;
+ }
+ protected function getCacheKey()
+ {
+ return $this->getID();
+ }
+ protected function cacheUrlManager($manager)
+ {
+ if($this->getEnableCache())
+ {
+ $cache = $this->getApplication()->getCache();
+ if($cache !== null)
+ {
+ $dependencies = null;
+ if($this->getApplication()->getMode() !== TApplicationMode::Performance)
+ if ($manager instanceof TUrlMapping && $fn = $manager->getConfigFile())
+ {
+ $fn = Prado::getPathOfNamespace($fn,$this->getApplication()->getConfigurationFileExt());
+ $dependencies = new TFileCacheDependency($fn);
+ }
+ return $cache->set($this->getCacheKey(), $manager, 0, $dependencies);
+ }
+ }
+ return false;
+ }
+ protected function loadCachedUrlManager()
+ {
+ if($this->getEnableCache())
+ {
+ $cache = $this->getApplication()->getCache();
+ if($cache !== null)
+ {
+ $manager = $cache->get($this->getCacheKey());
+ if($manager instanceof TUrlManager)
+ return $manager;
+ }
+ }
+ return null;
+ }
+ public function getUrlManager()
+ {
+ return $this->_urlManagerID;
+ }
+ public function setUrlManager($value)
+ {
+ $this->_urlManagerID=$value;
+ }
+ public function getUrlManagerModule()
+ {
+ if($this->_urlManager===null)
+ {
+ if(($this->_urlManager = $this->loadCachedUrlManager())===null)
+ {
+ if(empty($this->_urlManagerID))
+ {
+ $this->_urlManager=new TUrlManager;
+ $this->_urlManager->init(null);
+ }
+ else
+ {
+ $this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
+ if($this->_urlManager===null)
+ throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
+ if(!($this->_urlManager instanceof TUrlManager))
+ throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
+ }
+ $this->cacheUrlManager($this->_urlManager);
+ }
+ }
+ return $this->_urlManager;
+ }
+ public function getUrlFormat()
+ {
+ return $this->_urlFormat;
+ }
+ public function setUrlFormat($value)
+ {
+ $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
+ }
+ public function getUrlParamSeparator()
+ {
+ return $this->_separator;
+ }
+ public function setUrlParamSeparator($value)
+ {
+ if(strlen($value)===1)
+ $this->_separator=$value;
+ else
+ throw new TInvalidDataValueException('httprequest_separator_invalid');
+ }
+ public function getRequestType()
+ {
+ return isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:null;
+ }
+ public function getContentType($mimetypeOnly = true)
+ {
+ if(!isset($_SERVER['CONTENT_TYPE']))
+ return null;
+ if($mimetypeOnly === true && ($_pos = strpos(';', $_SERVER['CONTENT_TYPE'])) !== false)
+ return substr($_SERVER['CONTENT_TYPE'], 0, $_pos);
+ return $_SERVER['CONTENT_TYPE'];
+ }
+ public function getIsSecureConnection()
+ {
+ return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
+ }
+ public function getPathInfo()
+ {
+ return $this->_pathInfo;
+ }
+ public function getQueryString()
+ {
+ return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:null;
+ }
+ public function getHttpProtocolVersion()
+ {
+ return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:null;
+ }
+ public function getHeaders($case=null)
+ {
+ static $result;
+ if($result === null && function_exists('apache_request_headers')) {
+ $result = apache_request_headers();
+ }
+ elseif($result === null) {
+ $result = array();
+ foreach($_SERVER as $key=>$value) {
+ if(strncasecmp($key, 'HTTP_', 5) !== 0) continue;
+ $key = str_replace(' ','-', ucwords(strtolower(str_replace('_',' ', substr($key, 5)))));
+ $result[$key] = $value;
+ }
+ }
+ if($case !== null)
+ return array_change_key_case($result, $case);
+ return $result;
+ }
+ public function getRequestUri()
+ {
+ return $this->_requestUri;
+ }
+ public function getBaseUrl($forceSecureConnection=null)
+ {
+ $url=$this->getUrl();
+ $scheme=($forceSecureConnection)?"https": (($forceSecureConnection === null)?$url->getScheme():'http');
+ $host=$url->getHost();
+ if (($port=$url->getPort())) $host.=':'.$port;
+ return $scheme.'://'.$host;
+ }
+ public function getApplicationUrl()
+ {
+ if($this->_cgiFix&self::CGIFIX__SCRIPT_NAME && isset($_SERVER['ORIG_SCRIPT_NAME']))
+ return $_SERVER['ORIG_SCRIPT_NAME'];
+ return isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:null;
+ }
+ public function getAbsoluteApplicationUrl($forceSecureConnection=null)
+ {
+ return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
+ }
+ public function getApplicationFilePath()
+ {
+ return realpath(isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:null);
+ }
+ public function getServerName()
+ {
+ return isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:null;
+ }
+ public function getServerPort()
+ {
+ return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null;
+ }
+ public function getUrlReferrer()
+ {
+ return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
+ }
+ public function getBrowser()
+ {
+ try
+ {
+ return get_browser();
+ }
+ catch(TPhpErrorException $e)
+ {
+ throw new TConfigurationException('httprequest_browscap_required');
+ }
+ }
+ public function getUserAgent()
+ {
+ return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
+ }
+ public function getUserHostAddress()
+ {
+ return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null;
+ }
+ public function getUserHost()
+ {
+ return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
+ }
+ public function getAcceptTypes()
+ {
+ return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
+ }
+ public function getUserLanguages()
+ {
+ return Prado::getUserLanguages();
+ }
+ public function getEnableCookieValidation()
+ {
+ return $this->_enableCookieValidation;
+ }
+ public function setEnableCookieValidation($value)
+ {
+ $this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
+ }
+ public function getCgiFix()
+ {
+ return $this->_cgiFix;
+ }
+ public function setCgiFix($value)
+ {
+ $this->_cgiFix=TPropertyValue::ensureInteger($value);
+ }
+ public function getCookies()
+ {
+ if($this->_cookies===null)
+ {
+ $this->_cookies=new THttpCookieCollection;
+ if($this->getEnableCookieValidation())
+ {
+ $sm=$this->getApplication()->getSecurityManager();
+ foreach($_COOKIE as $key=>$value)
+ {
+ if(($value=$sm->validateData($value))!==false)
+ $this->_cookies->add(new THttpCookie($key,$value));
+ }
+ }
+ else
+ {
+ foreach($_COOKIE as $key=>$value)
+ $this->_cookies->add(new THttpCookie($key,$value));
+ }
+ }
+ return $this->_cookies;
+ }
+ public function getUploadedFiles()
+ {
+ return $_FILES;
+ }
+ public function getServerVariables()
+ {
+ return $_SERVER;
+ }
+ public function getEnvironmentVariables()
+ {
+ return $_ENV;
+ }
+ public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
+ {
+ if ($this->_cookieOnly===null)
+ $this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
+ $url=$this->getUrlManagerModule()->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
+ if(defined('SID') && SID != '' && !$this->_cookieOnly)
+ return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&amp;':'&')) . SID;
+ else
+ return $url;
+ }
+ protected function parseUrl()
+ {
+ return $this->getUrlManagerModule()->parseUrl();
+ }
+ public function resolveRequest($serviceIDs)
+ {
+ $getParams=$this->parseUrl();
+ foreach($getParams as $name=>$value)
+ $_GET[$name]=$value;
+ $this->_items=array_merge($_GET,$_POST);
+ $this->_requestResolved=true;
+ foreach($serviceIDs as $serviceID)
+ {
+ if($this->contains($serviceID))
+ {
+ $this->setServiceID($serviceID);
+ $this->setServiceParameter($this->itemAt($serviceID));
+ return $serviceID;
+ }
+ }
+ return null;
+ }
+ public function getRequestResolved()
+ {
+ return $this->_requestResolved;
+ }
+ public function getServiceID()
+ {
+ return $this->_serviceID;
+ }
+ public function setServiceID($value)
+ {
+ $this->_serviceID=$value;
+ }
+ public function getServiceParameter()
+ {
+ return $this->_serviceParam;
+ }
+ public function setServiceParameter($value)
+ {
+ $this->_serviceParam=$value;
+ }
+ public function getIterator()
+ {
+ return new TMapIterator($this->_items);
+ }
+ public function getCount()
+ {
+ return count($this->_items);
+ }
+ public function count()
+ {
+ return $this->getCount();
+ }
+ public function getKeys()
+ {
+ return array_keys($this->_items);
+ }
+ public function itemAt($key)
+ {
+ return isset($this->_items[$key]) ? $this->_items[$key] : null;
+ }
+ public function add($key,$value)
+ {
+ $this->_items[$key]=$value;
+ }
+ public function remove($key)
+ {
+ if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
+ {
+ $value=$this->_items[$key];
+ unset($this->_items[$key]);
+ return $value;
+ }
+ else
+ return null;
+ }
+ public function clear()
+ {
+ foreach(array_keys($this->_items) as $key)
+ $this->remove($key);
+ }
+ public function contains($key)
+ {
+ return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
+ }
+ public function toArray()
+ {
+ return $this->_items;
+ }
+ public function offsetExists($offset)
+ {
+ return $this->contains($offset);
+ }
+ public function offsetGet($offset)
+ {
+ return $this->itemAt($offset);
+ }
+ public function offsetSet($offset,$item)
+ {
+ $this->add($offset,$item);
+ }
+ public function offsetUnset($offset)
+ {
+ $this->remove($offset);
+ }
+}
+class THttpCookieCollection extends TList
+{
+ private $_o;
+ public function __construct($owner=null)
+ {
+ $this->_o=$owner;
+ }
+ public function insertAt($index,$item)
+ {
+ if($item instanceof THttpCookie)
+ {
+ parent::insertAt($index,$item);
+ if($this->_o instanceof THttpResponse)
+ $this->_o->addCookie($item);
+ }
+ else
+ throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
+ }
+ public function removeAt($index)
+ {
+ $item=parent::removeAt($index);
+ if($this->_o instanceof THttpResponse)
+ $this->_o->removeCookie($item);
+ return $item;
+ }
+ public function itemAt($index)
+ {
+ if(is_integer($index))
+ return parent::itemAt($index);
+ else
+ return $this->findCookieByName($index);
+ }
+ public function findCookieByName($name)
+ {
+ foreach($this as $cookie)
+ if($cookie->getName()===$name)
+ return $cookie;
+ return null;
+ }
+}
+class THttpCookie extends TComponent
+{
+ private $_domain='';
+ private $_name;
+ private $_value='';
+ private $_expire=0;
+ private $_path='/';
+ private $_secure=false;
+ private $_httpOnly=false;
+ public function __construct($name,$value)
+ {
+ $this->_name=$name;
+ $this->_value=$value;
+ }
+ public function getDomain()
+ {
+ return $this->_domain;
+ }
+ public function setDomain($value)
+ {
+ $this->_domain=$value;
+ }
+ public function getExpire()
+ {
+ return $this->_expire;
+ }
+ public function setExpire($value)
+ {
+ $this->_expire=TPropertyValue::ensureInteger($value);
+ }
+ public function getHttpOnly()
+ {
+ return $this->_httpOnly;
+ }
+ public function setHttpOnly($value)
+ {
+ $this->_httpOnly = TPropertyValue::ensureBoolean($value);
+ }
+ public function getName()
+ {
+ return $this->_name;
+ }
+ public function setName($value)
+ {
+ $this->_name=$value;
+ }
+ public function getValue()
+ {
+ return $this->_value;
+ }
+ public function setValue($value)
+ {
+ $this->_value=$value;
+ }
+ public function getPath()
+ {
+ return $this->_path;
+ }
+ public function setPath($value)
+ {
+ $this->_path=$value;
+ }
+ public function getSecure()
+ {
+ return $this->_secure;
+ }
+ public function setSecure($value)
+ {
+ $this->_secure=TPropertyValue::ensureBoolean($value);
+ }
+}
+class TUri extends TComponent
+{
+ private static $_defaultPort=array(
+ 'ftp'=>21,
+ 'gopher'=>70,
+ 'http'=>80,
+ 'https'=>443,
+ 'news'=>119,
+ 'nntp'=>119,
+ 'wais'=>210,
+ 'telnet'=>23
+ );
+ private $_scheme;
+ private $_host;
+ private $_port;
+ private $_user;
+ private $_pass;
+ private $_path;
+ private $_query;
+ private $_fragment;
+ private $_uri;
+ public function __construct($uri)
+ {
+ if(($ret=@parse_url($uri))!==false)
+ {
+ $this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
+ $this->_host=isset($ret['host'])?$ret['host']:'';
+ $this->_port=isset($ret['port'])?$ret['port']:'';
+ $this->_user=isset($ret['user'])?$ret['user']:'';
+ $this->_pass=isset($ret['pass'])?$ret['pass']:'';
+ $this->_path=isset($ret['path'])?$ret['path']:'';
+ $this->_query=isset($ret['query'])?$ret['query']:'';
+ $this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
+ $this->_uri=$uri;
+ }
+ else
+ {
+ throw new TInvalidDataValueException('uri_format_invalid',$uri);
+ }
+ }
+ public function getUri()
+ {
+ return $this->_uri;
+ }
+ public function getScheme()
+ {
+ return $this->_scheme;
+ }
+ public function getHost()
+ {
+ return $this->_host;
+ }
+ public function getPort()
+ {
+ return $this->_port;
+ }
+ public function getUser()
+ {
+ return $this->_user;
+ }
+ public function getPassword()
+ {
+ return $this->_pass;
+ }
+ public function getPath()
+ {
+ return $this->_path;
+ }
+ public function getQuery()
+ {
+ return $this->_query;
+ }
+ public function getFragment()
+ {
+ return $this->_fragment;
+ }
+}
+class THttpRequestUrlFormat extends TEnumerable
+{
+ const Get='Get';
+ const Path='Path';
+ const HiddenPath='HiddenPath';
+}
+class THttpResponseAdapter extends TApplicationComponent
+{
+ private $_response;
+ public function __construct($response)
+ {
+ $this->_response=$response;
+ }
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+ public function flushContent()
+ {
+ $this->_response->flushContent();
+ }
+ public function httpRedirect($url)
+ {
+ $this->_response->httpRedirect($url);
+ }
+ public function createNewHtmlWriter($type, $writer)
+ {
+ return $this->_response->createNewHtmlWriter($type,$writer);
+ }
+}
+class THttpResponse extends TModule implements ITextWriter
+{
+ const DEFAULT_CONTENTTYPE = 'text/html';
+ const DEFAULT_CHARSET = 'UTF-8';
+ private static $HTTP_STATUS_CODES = array(
+ 100 => 'Continue', 101 => 'Switching Protocols',
+ 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
+ 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
+ 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',
+ 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
+ );
+ private $_bufferOutput=true;
+ private $_initialized=false;
+ private $_cookies=null;
+ private $_status=200;
+ private $_reason='OK';
+ private $_htmlWriterType='System.Web.UI.THtmlWriter';
+ private $_contentType=null;
+ private $_charset='';
+ private $_adapter;
+ private $_httpHeaderSent;
+ private $_contentTypeHeaderSent;
+ public function __destruct()
+ {
+ }
+ public function setAdapter(THttpResponseAdapter $adapter)
+ {
+ $this->_adapter=$adapter;
+ }
+ public function getAdapter()
+ {
+ return $this->_adapter;
+ }
+ public function getHasAdapter()
+ {
+ return $this->_adapter!==null;
+ }
+ public function init($config)
+ {
+ if($this->_bufferOutput)
+ ob_start();
+ $this->_initialized=true;
+ $this->getApplication()->setResponse($this);
+ }
+ public function getCacheExpire()
+ {
+ return session_cache_expire();
+ }
+ public function setCacheExpire($value)
+ {
+ session_cache_expire(TPropertyValue::ensureInteger($value));
+ }
+ public function getCacheControl()
+ {
+ return session_cache_limiter();
+ }
+ public function setCacheControl($value)
+ {
+ session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
+ }
+ public function setContentType($type)
+ {
+ if ($this->_contentTypeHeaderSent)
+ throw new Exception('Unable to alter content-type as it has been already sent');
+ $this->_contentType = $type;
+ }
+ public function getContentType()
+ {
+ return $this->_contentType;
+ }
+ public function getCharset()
+ {
+ return $this->_charset;
+ }
+ public function setCharset($charset)
+ {
+ $this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
+ }
+ public function getBufferOutput()
+ {
+ return $this->_bufferOutput;
+ }
+ public function setBufferOutput($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
+ else
+ $this->_bufferOutput=TPropertyValue::ensureBoolean($value);
+ }
+ public function getStatusCode()
+ {
+ return $this->_status;
+ }
+ public function setStatusCode($status, $reason=null)
+ {
+ if ($this->_httpHeaderSent)
+ throw new Exception('Unable to alter response as HTTP header already sent');
+ $status=TPropertyValue::ensureInteger($status);
+ if(isset(self::$HTTP_STATUS_CODES[$status])) {
+ $this->_reason=self::$HTTP_STATUS_CODES[$status];
+ }else{
+ if($reason===null || $reason==='') {
+ throw new TInvalidDataValueException("response_status_reason_missing");
+ }
+ $reason=TPropertyValue::ensureString($reason);
+ if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
+ throw new TInvalidDataValueException("response_status_reason_barchars");
+ }
+ $this->_reason=$reason;
+ }
+ $this->_status=$status;
+ }
+ public function getStatusReason() {
+ return $this->_reason;
+ }
+ public function getCookies()
+ {
+ if($this->_cookies===null)
+ $this->_cookies=new THttpCookieCollection($this);
+ return $this->_cookies;
+ }
+ public function write($str)
+ {
+ if (!$this->_bufferOutput and !$this->_httpHeaderSent)
+ $this->ensureHeadersSent();
+ echo $str;
+ }
+ public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
+ {
+ static $defaultMimeTypes=array(
+ 'css'=>'text/css',
+ 'gif'=>'image/gif',
+ 'png'=>'image/png',
+ 'jpg'=>'image/jpeg',
+ 'jpeg'=>'image/jpeg',
+ 'htm'=>'text/html',
+ 'html'=>'text/html',
+ 'js'=>'javascript/js',
+ 'pdf'=>'application/pdf',
+ 'xls'=>'application/vnd.ms-excel',
+ );
+ if($mimeType===null)
+ {
+ $mimeType='text/plain';
+ if(function_exists('mime_content_type'))
+ $mimeType=mime_content_type($fileName);
+ else if(($ext=strrchr($fileName,'.'))!==false)
+ {
+ $ext=substr($ext,1);
+ if(isset($defaultMimeTypes[$ext]))
+ $mimeType=$defaultMimeTypes[$ext];
+ }
+ }
+ if($clientFileName===null)
+ $clientFileName=basename($fileName);
+ else
+ $clientFileName=basename($clientFileName);
+ if($fileSize===null || $fileSize < 0)
+ $fileSize = ($content===null?filesize($fileName):strlen($content));
+ $this->sendHttpHeader();
+ if(is_array($headers))
+ {
+ foreach($headers as $h)
+ header($h);
+ }
+ else
+ {
+ header('Pragma: public');
+ header('Expires: 0');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header("Content-Type: $mimeType");
+ $this->_contentTypeHeaderSent = true;
+ }
+ header('Content-Length: '.$fileSize);
+ header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
+ header('Content-Transfer-Encoding: binary');
+ if($content===null)
+ readfile($fileName);
+ else
+ echo $content;
+ }
+ public function redirect($url)
+ {
+ if($this->getHasAdapter())
+ $this->_adapter->httpRedirect($url);
+ else
+ $this->httpRedirect($url);
+ }
+ public function httpRedirect($url)
+ {
+ $this->ensureHeadersSent();
+ if($url[0]==='/')
+ $url=$this->getRequest()->getBaseUrl().$url;
+ if ($this->_status >= 300 && $this->_status < 400)
+ header('Location: '.str_replace('&amp;','&',$url), true, $this->_status);
+ else
+ header('Location: '.str_replace('&amp;','&',$url));
+ if(!$this->getApplication()->getRequestCompleted())
+ $this->getApplication()->onEndRequest();
+ exit();
+ }
+ public function reload()
+ {
+ $this->redirect($this->getRequest()->getRequestUri());
+ }
+ public function flush($continueBuffering = true)
+ {
+ if($this->getHasAdapter())
+ $this->_adapter->flushContent($continueBuffering);
+ else
+ $this->flushContent($continueBuffering);
+ }
+ public function ensureHeadersSent()
+ {
+ $this->ensureHttpHeaderSent();
+ $this->ensureContentTypeHeaderSent();
+ }
+ public function flushContent($continueBuffering = true)
+ {
+ $this->ensureHeadersSent();
+ if($this->_bufferOutput)
+ {
+ if (ob_get_length()>0)
+ {
+ if (!$continueBuffering)
+ {
+ $this->_bufferOutput = false;
+ ob_end_flush();
+ }
+ else
+ ob_flush();
+ flush();
+ }
+ }
+ else
+ flush();
+ }
+ protected function ensureHttpHeaderSent()
+ {
+ if (!$this->_httpHeaderSent)
+ $this->sendHttpHeader();
+ }
+ protected function sendHttpHeader()
+ {
+ $protocol=$this->getRequest()->getHttpProtocolVersion();
+ if($this->getRequest()->getHttpProtocolVersion() === null)
+ $protocol='HTTP/1.1';
+ $phpSapiName = substr(php_sapi_name(), 0, 3);
+ $cgi = $phpSapiName == 'cgi' || $phpSapiName == 'fpm';
+ header(($cgi ? 'Status:' : $protocol).' '.$this->_status.' '.$this->_reason, true, TPropertyValue::ensureInteger($this->_status));
+ $this->_httpHeaderSent = true;
+ }
+ protected function ensureContentTypeHeaderSent()
+ {
+ if (!$this->_contentTypeHeaderSent)
+ $this->sendContentTypeHeader();
+ }
+ protected function sendContentTypeHeader()
+ {
+ $contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
+ $charset=$this->getCharset();
+ if($charset === false) {
+ $this->appendHeader('Content-Type: '.$contentType);
+ return;
+ }
+ if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
+ $charset=$globalization->getCharset();
+ if($charset==='') $charset = self::DEFAULT_CHARSET;
+ $this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
+ $this->_contentTypeHeaderSent = true;
+ }
+ public function getContents()
+ {
+ return $this->_bufferOutput?ob_get_contents():'';
+ }
+ public function clear()
+ {
+ if($this->_bufferOutput)
+ ob_clean();
+ }
+ public function getHeaders($case=null)
+ {
+ $result = array();
+ $headers = headers_list();
+ foreach($headers as $header) {
+ $tmp = explode(':', $header);
+ $key = trim(array_shift($tmp));
+ $value = trim(implode(':', $tmp));
+ if(isset($result[$key]))
+ $result[$key] .= ', ' . $value;
+ else
+ $result[$key] = $value;
+ }
+ if($case !== null)
+ return array_change_key_case($result, $case);
+ return $result;
+ }
+ public function appendHeader($value, $replace=true)
+ {
+ header($value, $replace);
+ }
+ public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
+ {
+ error_log($message,$messageType,$destination,$extraHeaders);
+ }
+ public function addCookie($cookie)
+ {
+ $request=$this->getRequest();
+ if($request->getEnableCookieValidation())
+ {
+ $value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
+ setcookie(
+ $cookie->getName(),
+ $value,
+ $cookie->getExpire(),
+ $cookie->getPath(),
+ $cookie->getDomain(),
+ $cookie->getSecure(),
+ $cookie->getHttpOnly()
+ );
+ }
+ else {
+ setcookie(
+ $cookie->getName(),
+ $cookie->getValue(),
+ $cookie->getExpire(),
+ $cookie->getPath(),
+ $cookie->getDomain(),
+ $cookie->getSecure(),
+ $cookie->getHttpOnly()
+ );
+ }
+ }
+ public function removeCookie($cookie)
+ {
+ setcookie(
+ $cookie->getName(),
+ null,
+ 0,
+ $cookie->getPath(),
+ $cookie->getDomain(),
+ $cookie->getSecure(),
+ $cookie->getHttpOnly()
+ );
+ }
+ public function getHtmlWriterType()
+ {
+ return $this->_htmlWriterType;
+ }
+ public function setHtmlWriterType($value)
+ {
+ $this->_htmlWriterType=$value;
+ }
+ public function createHtmlWriter($type=null)
+ {
+ if($type===null)
+ $type=$this->getHtmlWriterType();
+ if($this->getHasAdapter())
+ return $this->_adapter->createNewHtmlWriter($type, $this);
+ else
+ return $this->createNewHtmlWriter($type, $this);
+ }
+ public function createNewHtmlWriter($type, $writer)
+ {
+ return Prado::createComponent($type, $writer);
+ }
+}
+class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
+{
+ private $_initialized=false;
+ private $_started=false;
+ private $_autoStart=false;
+ private $_cookie=null;
+ private $_id;
+ private $_customStorage=false;
+ public function getID()
+ {
+ return $this->_id;
+ }
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+ public function init($config)
+ {
+ if($this->_autoStart)
+ $this->open();
+ $this->_initialized=true;
+ $this->getApplication()->setSession($this);
+ register_shutdown_function(array($this, "close"));
+ }
+ public function open()
+ {
+ if(!$this->_started)
+ {
+ if($this->_customStorage)
+ session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
+ if($this->_cookie!==null)
+ session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure(),$this->_cookie->getHttpOnly());
+ if(ini_get('session.auto_start')!=='1')
+ session_start();
+ $this->_started=true;
+ }
+ }
+ public function close()
+ {
+ if($this->_started)
+ {
+ session_write_close();
+ $this->_started=false;
+ }
+ }
+ public function destroy()
+ {
+ if($this->_started)
+ {
+ session_destroy();
+ $this->_started=false;
+ }
+ }
+ public function regenerate($deleteOld=false)
+ {
+ $old = $this->getSessionID();
+ session_regenerate_id($deleteOld);
+ return $old;
+ }
+ public function getIsStarted()
+ {
+ return $this->_started;
+ }
+ public function getSessionID()
+ {
+ return session_id();
+ }
+ public function setSessionID($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
+ else
+ session_id($value);
+ }
+ public function getSessionName()
+ {
+ return session_name();
+ }
+ public function setSessionName($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
+ else if(ctype_alnum($value))
+ session_name($value);
+ else
+ throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
+ }
+ public function getSavePath()
+ {
+ return session_save_path();
+ }
+ public function setSavePath($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_savepath_unchangeable');
+ else if(is_dir($value))
+ session_save_path($value);
+ else
+ throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
+ }
+ public function getUseCustomStorage()
+ {
+ return $this->_customStorage;
+ }
+ public function setUseCustomStorage($value)
+ {
+ $this->_customStorage=TPropertyValue::ensureBoolean($value);
+ }
+ public function getCookie()
+ {
+ if($this->_cookie===null)
+ $this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
+ return $this->_cookie;
+ }
+ public function getCookieMode()
+ {
+ if(ini_get('session.use_cookies')==='0')
+ return THttpSessionCookieMode::None;
+ else if(ini_get('session.use_only_cookies')==='0')
+ return THttpSessionCookieMode::Allow;
+ else
+ return THttpSessionCookieMode::Only;
+ }
+ public function setCookieMode($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
+ else
+ {
+ $value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
+ if($value===THttpSessionCookieMode::None)
+ {
+ ini_set('session.use_cookies','0');
+ ini_set('session.use_only_cookies','0');
+ }
+ else if($value===THttpSessionCookieMode::Allow)
+ {
+ ini_set('session.use_cookies','1');
+ ini_set('session.use_only_cookies','0');
+ }
+ else
+ {
+ ini_set('session.use_cookies','1');
+ ini_set('session.use_only_cookies','1');
+ ini_set('session.use_trans_sid', 0);
+ }
+ }
+ }
+ public function getAutoStart()
+ {
+ return $this->_autoStart;
+ }
+ public function setAutoStart($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('httpsession_autostart_unchangeable');
+ else
+ $this->_autoStart=TPropertyValue::ensureBoolean($value);
+ }
+ public function getGCProbability()
+ {
+ return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
+ }
+ public function setGCProbability($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
+ else
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ if($value>=0 && $value<=100)
+ {
+ ini_set('session.gc_probability',$value);
+ ini_set('session.gc_divisor','100');
+ }
+ else
+ throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
+ }
+ }
+ public function getUseTransparentSessionID()
+ {
+ return ini_get('session.use_trans_sid')==='1';
+ }
+ public function setUseTransparentSessionID($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_transid_unchangeable');
+ else
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
+ throw new TInvalidOperationException('httpsession_transid_cookieonly');
+ ini_set('session.use_trans_sid',$value?'1':'0');
+ }
+ }
+ public function getTimeout()
+ {
+ return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
+ }
+ public function setTimeout($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
+ else
+ ini_set('session.gc_maxlifetime',$value);
+ }
+ public function _open($savePath,$sessionName)
+ {
+ return true;
+ }
+ public function _close()
+ {
+ return true;
+ }
+ public function _read($id)
+ {
+ return '';
+ }
+ public function _write($id,$data)
+ {
+ return true;
+ }
+ public function _destroy($id)
+ {
+ return true;
+ }
+ public function _gc($maxLifetime)
+ {
+ return true;
+ }
+ public function getIterator()
+ {
+ return new TSessionIterator;
+ }
+ public function getCount()
+ {
+ return count($_SESSION);
+ }
+ public function count()
+ {
+ return $this->getCount();
+ }
+ public function getKeys()
+ {
+ return array_keys($_SESSION);
+ }
+ public function itemAt($key)
+ {
+ return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
+ }
+ public function add($key,$value)
+ {
+ $_SESSION[$key]=$value;
+ }
+ public function remove($key)
+ {
+ if(isset($_SESSION[$key]))
+ {
+ $value=$_SESSION[$key];
+ unset($_SESSION[$key]);
+ return $value;
+ }
+ else
+ return null;
+ }
+ public function clear()
+ {
+ foreach(array_keys($_SESSION) as $key)
+ unset($_SESSION[$key]);
+ }
+ public function contains($key)
+ {
+ return isset($_SESSION[$key]);
+ }
+ public function toArray()
+ {
+ return $_SESSION;
+ }
+ public function offsetExists($offset)
+ {
+ return isset($_SESSION[$offset]);
+ }
+ public function offsetGet($offset)
+ {
+ return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
+ }
+ public function offsetSet($offset,$item)
+ {
+ $_SESSION[$offset]=$item;
+ }
+ public function offsetUnset($offset)
+ {
+ unset($_SESSION[$offset]);
+ }
+}
+class TSessionIterator implements Iterator
+{
+ private $_keys;
+ private $_key;
+ public function __construct()
+ {
+ $this->_keys=array_keys($_SESSION);
+ }
+ public function rewind()
+ {
+ $this->_key=reset($this->_keys);
+ }
+ public function key()
+ {
+ return $this->_key;
+ }
+ public function current()
+ {
+ return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
+ }
+ public function next()
+ {
+ do
+ {
+ $this->_key=next($this->_keys);
+ }
+ while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
+ }
+ public function valid()
+ {
+ return $this->_key!==false;
+ }
+}
+class THttpSessionCookieMode extends TEnumerable
+{
+ const None='None';
+ const Allow='Allow';
+ const Only='Only';
+}
+Prado::using('System.Web.UI.WebControls.*');
+class TAttributeCollection extends TMap
+{
+ private $_caseSensitive=false;
+ public function __get($name)
+ {
+ return $this->contains($name)?$this->itemAt($name):parent::__get($name);
+ }
+ public function __set($name,$value)
+ {
+ $this->add($name,$value);
+ }
+ public function getCaseSensitive()
+ {
+ return $this->_caseSensitive;
+ }
+ public function setCaseSensitive($value)
+ {
+ $this->_caseSensitive=TPropertyValue::ensureBoolean($value);
+ }
+ public function itemAt($key)
+ {
+ return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
+ }
+ public function add($key,$value)
+ {
+ parent::add($this->_caseSensitive?$key:strtolower($key),$value);
+ }
+ public function remove($key)
+ {
+ return parent::remove($this->_caseSensitive?$key:strtolower($key));
+ }
+ public function contains($key)
+ {
+ return parent::contains($this->_caseSensitive?$key:strtolower($key));
+ }
+ public function hasProperty($name)
+ {
+ return $this->contains($name) || parent::canGetProperty($name) || parent::canSetProperty($name);
+ }
+ public function canGetProperty($name)
+ {
+ return $this->contains($name) || parent::canGetProperty($name);
+ }
+ public function canSetProperty($name)
+ {
+ return true;
+ }
+}
+class TControlAdapter extends TApplicationComponent
+{
+ protected $_control;
+ public function __construct($control)
+ {
+ $this->_control=$control;
+ }
+ public function getControl()
+ {
+ return $this->_control;
+ }
+ public function getPage()
+ {
+ return $this->_control?$this->_control->getPage():null;
+ }
+ public function createChildControls()
+ {
+ $this->_control->createChildControls();
+ }
+ public function loadState()
+ {
+ $this->_control->loadState();
+ }
+ public function saveState()
+ {
+ $this->_control->saveState();
+ }
+ public function onInit($param)
+ {
+ $this->_control->onInit($param);
+ }
+ public function onLoad($param)
+ {
+ $this->_control->onLoad($param);
+ }
+ public function onPreRender($param)
+ {
+ $this->_control->onPreRender($param);
+ }
+ public function onUnload($param)
+ {
+ $this->_control->onUnload($param);
+ }
+ public function render($writer)
+ {
+ $this->_control->render($writer);
+ }
+ public function renderChildren($writer)
+ {
+ $this->_control->renderChildren($writer);
+ }
+}
+class TControl extends TApplicationComponent implements IRenderable, IBindable
+{
+ const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
+ const ID_SEPARATOR='$';
+ const CLIENT_ID_SEPARATOR='_';
+ const AUTOMATIC_ID_PREFIX='ctl';
+ const CS_CONSTRUCTED=0;
+ const CS_CHILD_INITIALIZED=1;
+ const CS_INITIALIZED=2;
+ const CS_STATE_LOADED=3;
+ const CS_LOADED=4;
+ const CS_PRERENDERED=5;
+ const IS_ID_SET=0x01;
+ const IS_DISABLE_VIEWSTATE=0x02;
+ const IS_SKIN_APPLIED=0x04;
+ const IS_STYLESHEET_APPLIED=0x08;
+ const IS_DISABLE_THEMING=0x10;
+ const IS_CHILD_CREATED=0x20;
+ const IS_CREATING_CHILD=0x40;
+ const RF_CONTROLS=0; const RF_CHILD_STATE=1; const RF_NAMED_CONTROLS=2; const RF_NAMED_CONTROLS_ID=3; const RF_SKIN_ID=4; const RF_DATA_BINDINGS=5; const RF_EVENTS=6; const RF_CONTROLSTATE=7; const RF_NAMED_OBJECTS=8; const RF_ADAPTER=9; const RF_AUTO_BINDINGS=10;
+ private $_id='';
+ private $_uid;
+ private $_parent;
+ private $_page;
+ private $_namingContainer;
+ private $_tplControl;
+ private $_viewState=array();
+ private $_tempState=array();
+ private $_trackViewState=true;
+ private $_stage=0;
+ private $_flags=0;
+ private $_rf=array();
+ public function __get($name)
+ {
+ if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
+ return $this->_rf[self::RF_NAMED_OBJECTS][$name];
+ else
+ return parent::__get($name);
+ }
+ public function getHasAdapter()
+ {
+ return isset($this->_rf[self::RF_ADAPTER]);
+ }
+ public function getAdapter()
+ {
+ return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
+ }
+ public function setAdapter(TControlAdapter $adapter)
+ {
+ $this->_rf[self::RF_ADAPTER]=$adapter;
+ }
+ public function getParent()
+ {
+ return $this->_parent;
+ }
+ public function getNamingContainer()
+ {
+ if(!$this->_namingContainer && $this->_parent)
+ {
+ if($this->_parent instanceof INamingContainer)
+ $this->_namingContainer=$this->_parent;
+ else
+ $this->_namingContainer=$this->_parent->getNamingContainer();
+ }
+ return $this->_namingContainer;
+ }
+ public function getPage()
+ {
+ if(!$this->_page)
+ {
+ if($this->_parent)
+ $this->_page=$this->_parent->getPage();
+ else if($this->_tplControl)
+ $this->_page=$this->_tplControl->getPage();
+ }
+ return $this->_page;
+ }
+ public function setPage($page)
+ {
+ $this->_page=$page;
+ }
+ public function setTemplateControl($control)
+ {
+ $this->_tplControl=$control;
+ }
+ public function getTemplateControl()
+ {
+ if(!$this->_tplControl && $this->_parent)
+ $this->_tplControl=$this->_parent->getTemplateControl();
+ return $this->_tplControl;
+ }
+ public function getSourceTemplateControl()
+ {
+ $control=$this;
+ while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
+ {
+ if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
+ return $control;
+ }
+ return $this->getPage();
+ }
+ protected function getControlStage()
+ {
+ return $this->_stage;
+ }
+ protected function setControlStage($value)
+ {
+ $this->_stage=$value;
+ }
+ public function getID($hideAutoID=true)
+ {
+ if($hideAutoID)
+ return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
+ else
+ return $this->_id;
+ }
+ public function setID($id)
+ {
+ if(!preg_match(self::ID_FORMAT,$id))
+ throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
+ $this->_id=$id;
+ $this->_flags |= self::IS_ID_SET;
+ $this->clearCachedUniqueID($this instanceof INamingContainer);
+ if($this->_namingContainer)
+ $this->_namingContainer->clearNameTable();
+ }
+ public function getUniqueID()
+ {
+ if($this->_uid==='' || $this->_uid===null) {
+ $this->_uid=''; if($namingContainer=$this->getNamingContainer())
+ {
+ if($this->getPage()===$namingContainer)
+ return ($this->_uid=$this->_id);
+ else if(($prefix=$namingContainer->getUniqueID())==='')
+ return $this->_id;
+ else
+ return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
+ }
+ else return $this->_id;
+ }
+ else
+ return $this->_uid;
+ }
+ public function focus()
+ {
+ $this->getPage()->setFocus($this);
+ }
+ public function getClientID()
+ {
+ return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
+ }
+ public static function convertUniqueIdToClientId($uniqueID)
+ {
+ return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
+ }
+ public function getSkinID()
+ {
+ return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
+ }
+ public function setSkinID($value)
+ {
+ if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
+ throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
+ else
+ $this->_rf[self::RF_SKIN_ID]=$value;
+ }
+ public function getIsSkinApplied()
+ {
+ return ($this->_flags & self::IS_SKIN_APPLIED);
+ }
+ public function getEnableTheming()
+ {
+ if($this->_flags & self::IS_DISABLE_THEMING)
+ return false;
+ else
+ return $this->_parent?$this->_parent->getEnableTheming():true;
+ }
+ public function setEnableTheming($value)
+ {
+ if($this->_stage>=self::CS_CHILD_INITIALIZED)
+ throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
+ else if(TPropertyValue::ensureBoolean($value))
+ $this->_flags &= ~self::IS_DISABLE_THEMING;
+ else
+ $this->_flags |= self::IS_DISABLE_THEMING;
+ }
+ public function getCustomData()
+ {
+ return $this->getViewState('CustomData',null);
+ }
+ public function setCustomData($value)
+ {
+ $this->setViewState('CustomData',$value,null);
+ }
+ public function getHasControls()
+ {
+ return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
+ }
+ public function getControls()
+ {
+ if(!isset($this->_rf[self::RF_CONTROLS]))
+ $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
+ return $this->_rf[self::RF_CONTROLS];
+ }
+ protected function createControlCollection()
+ {
+ return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
+ }
+ public function getVisible($checkParents=true)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control;$control=$control->_parent)
+ if(!$control->getVisible(false))
+ return false;
+ return true;
+ }
+ else
+ return $this->getViewState('Visible',true);
+ }
+ public function setVisible($value)
+ {
+ $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
+ }
+ public function getEnabled($checkParents=false)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control;$control=$control->_parent)
+ if(!$control->getViewState('Enabled',true))
+ return false;
+ return true;
+ }
+ else
+ return $this->getViewState('Enabled',true);
+ }
+ public function setEnabled($value)
+ {
+ $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
+ }
+ public function getHasAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->getCount()>0;
+ else
+ return false;
+ }
+ public function getAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('Attributes',$attributes,null);
+ return $attributes;
+ }
+ }
+ public function hasAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->contains($name);
+ else
+ return false;
+ }
+ public function getAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->itemAt($name);
+ else
+ return null;
+ }
+ public function setAttribute($name,$value)
+ {
+ $this->getAttributes()->add($name,$value);
+ }
+ public function removeAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->remove($name);
+ else
+ return null;
+ }
+ public function getEnableViewState($checkParents=false)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control!==null;$control=$control->getParent())
+ if($control->_flags & self::IS_DISABLE_VIEWSTATE)
+ return false;
+ return true;
+ }
+ else
+ return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
+ }
+ public function setEnableViewState($value)
+ {
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
+ else
+ $this->_flags |= self::IS_DISABLE_VIEWSTATE;
+ }
+ protected function getControlState($key,$defaultValue=null)
+ {
+ return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
+ }
+ protected function setControlState($key,$value,$defaultValue=null)
+ {
+ if($value===$defaultValue)
+ unset($this->_rf[self::RF_CONTROLSTATE][$key]);
+ else
+ $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
+ }
+ protected function clearControlState($key)
+ {
+ unset($this->_rf[self::RF_CONTROLSTATE][$key]);
+ }
+ public function trackViewState($enabled)
+ {
+ $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
+ }
+ public function getViewState($key,$defaultValue=null)
+ {
+ if(isset($this->_viewState[$key]))
+ return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
+ else if(isset($this->_tempState[$key]))
+ {
+ if(is_object($this->_tempState[$key]) && $this->_trackViewState)
+ $this->_viewState[$key]=$this->_tempState[$key];
+ return $this->_tempState[$key];
+ }
+ else
+ return $defaultValue;
+ }
+ public function setViewState($key,$value,$defaultValue=null)
+ {
+ if($this->_trackViewState)
+ {
+ $this->_viewState[$key]=$value;
+ unset($this->_tempState[$key]);
+ }
+ else
+ {
+ unset($this->_viewState[$key]);
+ $this->_tempState[$key]=$value;
+ }
+ }
+ public function clearViewState($key)
+ {
+ unset($this->_viewState[$key]);
+ unset($this->_tempState[$key]);
+ }
+ public function bindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
+ }
+ public function unbindProperty($name)
+ {
+ unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
+ }
+ public function autoBindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
+ }
+ public function dataBind()
+ {
+ $this->dataBindProperties();
+ $this->onDataBinding(null);
+ $this->dataBindChildren();
+ }
+ protected function dataBindProperties()
+ {
+ if(isset($this->_rf[self::RF_DATA_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+ protected function autoDataBindProperties()
+ {
+ if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+ protected function dataBindChildren()
+ {
+ if(isset($this->_rf[self::RF_CONTROLS]))
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof IBindable)
+ $control->dataBind();
+ }
+ }
+ final protected function getChildControlsCreated()
+ {
+ return ($this->_flags & self::IS_CHILD_CREATED)!==0;
+ }
+ final protected function setChildControlsCreated($value)
+ {
+ if($value)
+ $this->_flags |= self::IS_CHILD_CREATED;
+ else
+ {
+ if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
+ $this->getControls()->clear();
+ $this->_flags &= ~self::IS_CHILD_CREATED;
+ }
+ }
+ public function ensureChildControls()
+ {
+ if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
+ {
+ try
+ {
+ $this->_flags |= self::IS_CREATING_CHILD;
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->createChildControls();
+ else
+ $this->createChildControls();
+ $this->_flags &= ~self::IS_CREATING_CHILD;
+ $this->_flags |= self::IS_CHILD_CREATED;
+ }
+ catch(Exception $e)
+ {
+ $this->_flags &= ~self::IS_CREATING_CHILD;
+ $this->_flags |= self::IS_CHILD_CREATED;
+ throw $e;
+ }
+ }
+ }
+ public function createChildControls()
+ {
+ }
+ public function findControl($id)
+ {
+ $id=strtr($id,'.',self::ID_SEPARATOR);
+ $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
+ if(!$container || !$container->getHasControls())
+ return null;
+ if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
+ {
+ $container->_rf[self::RF_NAMED_CONTROLS]=array();
+ $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
+ }
+ if(($pos=strpos($id,self::ID_SEPARATOR))===false)
+ return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
+ else
+ {
+ $cid=substr($id,0,$pos);
+ $sid=substr($id,$pos+1);
+ if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
+ return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
+ else
+ return null;
+ }
+ }
+ public function findControlsByType($type,$strict=true)
+ {
+ $controls=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
+ $controls[]=$control;
+ if(($control instanceof TControl) && $control->getHasControls())
+ $controls=array_merge($controls,$control->findControlsByType($type,$strict));
+ }
+ }
+ return $controls;
+ }
+ public function findControlsByID($id)
+ {
+ $controls=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if($control->_id===$id)
+ $controls[]=$control;
+ $controls=array_merge($controls,$control->findControlsByID($id));
+ }
+ }
+ }
+ return $controls;
+ }
+ public function clearNamingContainer()
+ {
+ unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
+ $this->clearNameTable();
+ }
+ public function registerObject($name,$object)
+ {
+ if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
+ throw new TInvalidOperationException('control_object_reregistered',$name);
+ $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
+ }
+ public function unregisterObject($name)
+ {
+ unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
+ }
+ public function isObjectRegistered($name)
+ {
+ return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
+ }
+ public function getHasChildInitialized()
+ {
+ return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
+ }
+ public function getHasInitialized()
+ {
+ return $this->getControlStage() >= self::CS_INITIALIZED;
+ }
+ public function getHasLoadedPostData()
+ {
+ return $this->getControlStage() >= self::CS_STATE_LOADED;
+ }
+ public function getHasLoaded()
+ {
+ return $this->getControlStage() >= self::CS_LOADED;
+ }
+ public function getHasPreRendered()
+ {
+ return $this->getControlStage() >= self::CS_PRERENDERED;
+ }
+ public function getRegisteredObject($name)
+ {
+ return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
+ }
+ public function getAllowChildControls()
+ {
+ return true;
+ }
+ public function addParsedObject($object)
+ {
+ $this->getControls()->add($object);
+ }
+ final protected function clearChildState()
+ {
+ unset($this->_rf[self::RF_CHILD_STATE]);
+ }
+ final protected function isDescendentOf($ancestor)
+ {
+ $control=$this;
+ while($control!==$ancestor && $control->_parent)
+ $control=$control->_parent;
+ return $control===$ancestor;
+ }
+ public function addedControl($control)
+ {
+ if($control->_parent)
+ $control->_parent->getControls()->remove($control);
+ $control->_parent=$this;
+ $control->_page=$this->getPage();
+ $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
+ if($namingContainer)
+ {
+ $control->_namingContainer=$namingContainer;
+ if($control->_id==='')
+ $control->generateAutomaticID();
+ else
+ $namingContainer->clearNameTable();
+ $control->clearCachedUniqueID($control instanceof INamingContainer);
+ }
+ if($this->_stage>=self::CS_CHILD_INITIALIZED)
+ {
+ $control->initRecursive($namingContainer);
+ if($this->_stage>=self::CS_STATE_LOADED)
+ {
+ if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
+ {
+ $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
+ unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
+ }
+ else
+ $state=null;
+ $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ if($this->_stage>=self::CS_LOADED)
+ {
+ $control->loadRecursive();
+ if($this->_stage>=self::CS_PRERENDERED)
+ $control->preRenderRecursive();
+ }
+ }
+ }
+ }
+ public function removedControl($control)
+ {
+ if($this->_namingContainer)
+ $this->_namingContainer->clearNameTable();
+ $control->unloadRecursive();
+ $control->_parent=null;
+ $control->_page=null;
+ $control->_namingContainer=null;
+ $control->_tplControl=null;
+ if(!($control->_flags & self::IS_ID_SET))
+ $control->_id='';
+ else
+ unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
+ $control->clearCachedUniqueID(true);
+ }
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ if($this->getHasControls())
+ {
+ if($this instanceof INamingContainer)
+ $namingContainer=$this;
+ $page=$this->getPage();
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ $control->_namingContainer=$namingContainer;
+ $control->_page=$page;
+ if($control->_id==='' && $namingContainer)
+ $control->generateAutomaticID();
+ $control->initRecursive($namingContainer);
+ }
+ }
+ }
+ if($this->_stage<self::CS_INITIALIZED)
+ {
+ $this->_stage=self::CS_CHILD_INITIALIZED;
+ if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
+ {
+ $page->applyControlSkin($this);
+ $this->_flags |= self::IS_SKIN_APPLIED;
+ }
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onInit(null);
+ else
+ $this->onInit(null);
+ $this->_stage=self::CS_INITIALIZED;
+ }
+ }
+ protected function loadRecursive()
+ {
+ if($this->_stage<self::CS_LOADED)
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onLoad(null);
+ else
+ $this->onLoad(null);
+ }
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->loadRecursive();
+ }
+ }
+ if($this->_stage<self::CS_LOADED)
+ $this->_stage=self::CS_LOADED;
+ }
+ protected function preRenderRecursive()
+ {
+ $this->autoDataBindProperties();
+ if($this->getVisible(false))
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onPreRender(null);
+ else
+ $this->onPreRender(null);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->preRenderRecursive();
+ else if($control instanceof TCompositeLiteral)
+ $control->evaluateDynamicContent();
+ }
+ }
+ }
+ $this->_stage=self::CS_PRERENDERED;
+ }
+ protected function unloadRecursive()
+ {
+ if(!($this->_flags & self::IS_ID_SET))
+ $this->_id='';
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof TControl)
+ $control->unloadRecursive();
+ }
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onUnload(null);
+ else
+ $this->onUnload(null);
+ }
+ public function onInit($param)
+ {
+ $this->raiseEvent('OnInit',$this,$param);
+ }
+ public function onLoad($param)
+ {
+ $this->raiseEvent('OnLoad',$this,$param);
+ }
+ public function onDataBinding($param)
+ {
+ $this->raiseEvent('OnDataBinding',$this,$param);
+ }
+ public function onUnload($param)
+ {
+ $this->raiseEvent('OnUnload',$this,$param);
+ }
+ public function onPreRender($param)
+ {
+ $this->raiseEvent('OnPreRender',$this,$param);
+ }
+ protected function raiseBubbleEvent($sender,$param)
+ {
+ $control=$this;
+ while($control=$control->_parent)
+ {
+ if($control->bubbleEvent($sender,$param))
+ break;
+ }
+ }
+ public function bubbleEvent($sender,$param)
+ {
+ return false;
+ }
+ public function broadcastEvent($name,$sender,$param)
+ {
+ $rootControl=(($page=$this->getPage())===null)?$this:$page;
+ $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
+ }
+ private function broadcastEventInternal($name,$sender,$param)
+ {
+ if($this->hasEvent($name))
+ $this->raiseEvent($name,$sender,$param->getParameter());
+ if($this instanceof IBroadcastEventReceiver)
+ $this->broadcastEventReceived($sender,$param);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->broadcastEventInternal($name,$sender,$param);
+ }
+ }
+ }
+ protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
+ {
+ if($preCallback!==null)
+ call_user_func($preCallback,$this,$param);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ $control->traverseChildControls($param,$preCallback,$postCallback);
+ }
+ }
+ }
+ if($postCallback!==null)
+ call_user_func($postCallback,$this,$param);
+ }
+ public function renderControl($writer)
+ {
+ if($this instanceof IActiveControl || $this->getVisible(false))
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->render($writer);
+ else
+ $this->render($writer);
+ }
+ }
+ public function render($writer)
+ {
+ $this->renderChildren($writer);
+ }
+ public function renderChildren($writer)
+ {
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if(is_string($control))
+ $writer->write($control);
+ else if($control instanceof TControl)
+ $control->renderControl($writer);
+ else if($control instanceof IRenderable)
+ $control->render($writer);
+ }
+ }
+ }
+ public function saveState()
+ {
+ }
+ public function loadState()
+ {
+ }
+ protected function loadStateRecursive(&$state,$needViewState=true)
+ {
+ if(is_array($state))
+ {
+ $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ if(isset($state[1]))
+ {
+ $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
+ unset($state[1]);
+ }
+ else
+ unset($this->_rf[self::RF_CONTROLSTATE]);
+ if($needViewState)
+ {
+ if(isset($state[0]))
+ $this->_viewState=&$state[0];
+ else
+ $this->_viewState=array();
+ }
+ unset($state[0]);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if(isset($state[$control->_id]))
+ {
+ $control->loadStateRecursive($state[$control->_id],$needViewState);
+ unset($state[$control->_id]);
+ }
+ }
+ }
+ }
+ if(!empty($state))
+ $this->_rf[self::RF_CHILD_STATE]=&$state;
+ }
+ $this->_stage=self::CS_STATE_LOADED;
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->loadState();
+ else
+ $this->loadState();
+ }
+ protected function &saveStateRecursive($needViewState=true)
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->saveState();
+ else
+ $this->saveState();
+ $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ $state=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $state[$control->_id]=&$control->saveStateRecursive($needViewState);
+ }
+ }
+ if($needViewState && !empty($this->_viewState))
+ $state[0]=&$this->_viewState;
+ if(isset($this->_rf[self::RF_CONTROLSTATE]))
+ $state[1]=&$this->_rf[self::RF_CONTROLSTATE];
+ return $state;
+ }
+ public function applyStyleSheetSkin($page)
+ {
+ if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
+ {
+ $page->applyControlStyleSheet($this);
+ $this->_flags |= self::IS_STYLESHEET_APPLIED;
+ }
+ else if($this->_flags & self::IS_STYLESHEET_APPLIED)
+ throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
+ }
+ private function clearCachedUniqueID($recursive)
+ {
+ if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof TControl)
+ $control->clearCachedUniqueID($recursive);
+ }
+ $this->_uid=null;
+ }
+ private function generateAutomaticID()
+ {
+ $this->_flags &= ~self::IS_ID_SET;
+ if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
+ $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
+ $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
+ $this->_id=self::AUTOMATIC_ID_PREFIX . $id;
+ $this->_namingContainer->clearNameTable();
+ }
+ private function clearNameTable()
+ {
+ unset($this->_rf[self::RF_NAMED_CONTROLS]);
+ }
+ private function fillNameTable($container,$controls)
+ {
+ foreach($controls as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if($control->_id!=='')
+ {
+ if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
+ throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
+ else
+ $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
+ }
+ if(!($control instanceof INamingContainer) && $control->getHasControls())
+ $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
+ }
+ }
+ }
+}
+class TControlCollection extends TList
+{
+ private $_o;
+ public function __construct(TControl $owner,$readOnly=false)
+ {
+ $this->_o=$owner;
+ parent::__construct(null,$readOnly);
+ }
+ protected function getOwner()
+ {
+ return $this->_o;
+ }
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TControl)
+ {
+ parent::insertAt($index,$item);
+ $this->_o->addedControl($item);
+ }
+ else if(is_string($item) || ($item instanceof IRenderable))
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('controlcollection_control_required');
+ }
+ public function removeAt($index)
+ {
+ $item=parent::removeAt($index);
+ if($item instanceof TControl)
+ $this->_o->removedControl($item);
+ return $item;
+ }
+ public function clear()
+ {
+ parent::clear();
+ if($this->_o instanceof INamingContainer)
+ $this->_o->clearNamingContainer();
+ }
+}
+class TEmptyControlCollection extends TControlCollection
+{
+ public function __construct(TControl $owner)
+ {
+ parent::__construct($owner,true);
+ }
+ public function insertAt($index,$item)
+ {
+ if(!is_string($item)) parent::insertAt($index,$item); }
+}
+interface INamingContainer
+{
+}
+interface IPostBackEventHandler
+{
+ public function raisePostBackEvent($param);
+}
+interface IPostBackDataHandler
+{
+ public function loadPostData($key,$values);
+ public function raisePostDataChangedEvent();
+ public function getDataChanged();
+}
+interface IValidator
+{
+ public function validate();
+ public function getIsValid();
+ public function setIsValid($value);
+ public function getErrorMessage();
+ public function setErrorMessage($value);
+}
+interface IValidatable
+{
+ public function getValidationPropertyValue();
+ public function getIsValid();
+ public function setIsValid($value);
+}
+interface IBroadcastEventReceiver
+{
+ public function broadcastEventReceived($sender,$param);
+}
+interface ITheme
+{
+ public function applySkin($control);
+}
+interface ITemplate
+{
+ public function instantiateIn($parent);
+}
+interface IButtonControl
+{
+ public function getText();
+ public function setText($value);
+ public function getCausesValidation();
+ public function setCausesValidation($value);
+ public function getCommandName();
+ public function setCommandName($value);
+ public function getCommandParameter();
+ public function setCommandParameter($value);
+ public function getValidationGroup();
+ public function setValidationGroup($value);
+ public function onClick($param);
+ public function onCommand($param);
+ public function setIsDefaultButton($value);
+ public function getIsDefaultButton();
+}
+interface ISurroundable
+{
+ public function getSurroundingTag();
+ public function getSurroundingTagID();
+}
+class TBroadcastEventParameter extends TEventParameter
+{
+ private $_name;
+ private $_param;
+ public function __construct($name='',$parameter=null)
+ {
+ $this->_name=$name;
+ $this->_param=$parameter;
+ }
+ public function getName()
+ {
+ return $this->_name;
+ }
+ public function setName($value)
+ {
+ $this->_name=$value;
+ }
+ public function getParameter()
+ {
+ return $this->_param;
+ }
+ public function setParameter($value)
+ {
+ $this->_param=$value;
+ }
+}
+class TCommandEventParameter extends TEventParameter
+{
+ private $_name;
+ private $_param;
+ public function __construct($name='',$parameter='')
+ {
+ $this->_name=$name;
+ $this->_param=$parameter;
+ }
+ public function getCommandName()
+ {
+ return $this->_name;
+ }
+ public function getCommandParameter()
+ {
+ return $this->_param;
+ }
+}
+class TCompositeLiteral extends TComponent implements IRenderable, IBindable
+{
+ const TYPE_EXPRESSION=0;
+ const TYPE_STATEMENTS=1;
+ const TYPE_DATABINDING=2;
+ private $_container=null;
+ private $_items=array();
+ private $_expressions=array();
+ private $_statements=array();
+ private $_bindings=array();
+ public function __construct($items)
+ {
+ $this->_items=array();
+ $this->_expressions=array();
+ $this->_statements=array();
+ foreach($items as $id=>$item)
+ {
+ if(is_array($item))
+ {
+ if($item[0]===self::TYPE_EXPRESSION)
+ $this->_expressions[$id]=$item[1];
+ else if($item[0]===self::TYPE_STATEMENTS)
+ $this->_statements[$id]=$item[1];
+ else if($item[0]===self::TYPE_DATABINDING)
+ $this->_bindings[$id]=$item[1];
+ $this->_items[$id]='';
+ }
+ else
+ $this->_items[$id]=$item;
+ }
+ }
+ public function getContainer()
+ {
+ return $this->_container;
+ }
+ public function setContainer(TComponent $value)
+ {
+ $this->_container=$value;
+ }
+ public function evaluateDynamicContent()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_expressions as $id=>$expression)
+ $this->_items[$id]=$context->evaluateExpression($expression);
+ foreach($this->_statements as $id=>$statement)
+ $this->_items[$id]=$context->evaluateStatements($statement);
+ }
+ public function dataBind()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_bindings as $id=>$binding)
+ $this->_items[$id]=$context->evaluateExpression($binding);
+ }
+ public function render($writer)
+ {
+ $writer->write(implode('',$this->_items));
+ }
+}
+class TFont extends TComponent
+{
+ const IS_BOLD=0x01;
+ const IS_ITALIC=0x02;
+ const IS_OVERLINE=0x04;
+ const IS_STRIKEOUT=0x08;
+ const IS_UNDERLINE=0x10;
+ const IS_SET_BOLD=0x01000;
+ const IS_SET_ITALIC=0x02000;
+ const IS_SET_OVERLINE=0x04000;
+ const IS_SET_STRIKEOUT=0x08000;
+ const IS_SET_UNDERLINE=0x10000;
+ const IS_SET_SIZE=0x20000;
+ const IS_SET_NAME=0x40000;
+ private $_flags=0;
+ private $_name='';
+ private $_size='';
+ public function getBold()
+ {
+ return ($this->_flags & self::IS_BOLD)!==0;
+ }
+ public function setBold($value)
+ {
+ $this->_flags |= self::IS_SET_BOLD;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_BOLD;
+ else
+ $this->_flags &= ~self::IS_BOLD;
+ }
+ public function getItalic()
+ {
+ return ($this->_flags & self::IS_ITALIC)!==0;
+ }
+ public function setItalic($value)
+ {
+ $this->_flags |= self::IS_SET_ITALIC;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_ITALIC;
+ else
+ $this->_flags &= ~self::IS_ITALIC;
+ }
+ public function getOverline()
+ {
+ return ($this->_flags & self::IS_OVERLINE)!==0;
+ }
+ public function setOverline($value)
+ {
+ $this->_flags |= self::IS_SET_OVERLINE;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_OVERLINE;
+ else
+ $this->_flags &= ~self::IS_OVERLINE;
+ }
+ public function getSize()
+ {
+ return $this->_size;
+ }
+ public function setSize($value)
+ {
+ $this->_flags |= self::IS_SET_SIZE;
+ $this->_size=$value;
+ }
+ public function getStrikeout()
+ {
+ return ($this->_flags & self::IS_STRIKEOUT)!==0;
+ }
+ public function setStrikeout($value)
+ {
+ $this->_flags |= self::IS_SET_STRIKEOUT;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_STRIKEOUT;
+ else
+ $this->_flags &= ~self::IS_STRIKEOUT;
+ }
+ public function getUnderline()
+ {
+ return ($this->_flags & self::IS_UNDERLINE)!==0;
+ }
+ public function setUnderline($value)
+ {
+ $this->_flags |= self::IS_SET_UNDERLINE;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_UNDERLINE;
+ else
+ $this->_flags &= ~self::IS_UNDERLINE;
+ }
+ public function getName()
+ {
+ return $this->_name;
+ }
+ public function setName($value)
+ {
+ $this->_flags |= self::IS_SET_NAME;
+ $this->_name=$value;
+ }
+ public function getIsEmpty()
+ {
+ return !$this->_flags;
+ }
+ public function reset()
+ {
+ $this->_flags=0;
+ $this->_name='';
+ $this->_size='';
+ }
+ public function mergeWith($font)
+ {
+ if($font===null || $font->_flags===0)
+ return;
+ if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
+ $this->setBold($font->getBold());
+ if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
+ $this->setItalic($font->getItalic());
+ if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
+ $this->setOverline($font->getOverline());
+ if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
+ $this->setStrikeout($font->getStrikeout());
+ if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
+ $this->setUnderline($font->getUnderline());
+ if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
+ $this->setSize($font->getSize());
+ if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
+ $this->setName($font->getName());
+ }
+ public function copyFrom($font)
+ {
+ if($font===null || $font->_flags===0)
+ return;
+ if($font->_flags & self::IS_SET_BOLD)
+ $this->setBold($font->getBold());
+ if($font->_flags & self::IS_SET_ITALIC)
+ $this->setItalic($font->getItalic());
+ if($font->_flags & self::IS_SET_OVERLINE)
+ $this->setOverline($font->getOverline());
+ if($font->_flags & self::IS_SET_STRIKEOUT)
+ $this->setStrikeout($font->getStrikeout());
+ if($font->_flags & self::IS_SET_UNDERLINE)
+ $this->setUnderline($font->getUnderline());
+ if($font->_flags & self::IS_SET_SIZE)
+ $this->setSize($font->getSize());
+ if($font->_flags & self::IS_SET_NAME)
+ $this->setName($font->getName());
+ }
+ public function toString()
+ {
+ if($this->_flags===0)
+ return '';
+ $str='';
+ if($this->_flags & self::IS_SET_BOLD)
+ $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
+ if($this->_flags & self::IS_SET_ITALIC)
+ $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
+ $textDec='';
+ if($this->_flags & self::IS_UNDERLINE)
+ $textDec.='underline';
+ if($this->_flags & self::IS_OVERLINE)
+ $textDec.=' overline';
+ if($this->_flags & self::IS_STRIKEOUT)
+ $textDec.=' line-through';
+ $textDec=ltrim($textDec);
+ if($textDec!=='')
+ $str.='text-decoration:'.$textDec.';';
+ if($this->_size!=='')
+ $str.='font-size:'.$this->_size.';';
+ if($this->_name!=='')
+ $str.='font-family:'.$this->_name.';';
+ return $str;
+ }
+ public function addAttributesToRender($writer)
+ {
+ if($this->_flags===0)
+ return;
+ if($this->_flags & self::IS_SET_BOLD)
+ $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
+ if($this->_flags & self::IS_SET_ITALIC)
+ $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
+ $textDec='';
+ if($this->_flags & self::IS_UNDERLINE)
+ $textDec.='underline';
+ if($this->_flags & self::IS_OVERLINE)
+ $textDec.=' overline';
+ if($this->_flags & self::IS_STRIKEOUT)
+ $textDec.=' line-through';
+ $textDec=ltrim($textDec);
+ if($textDec!=='')
+ $writer->addStyleAttribute('text-decoration',$textDec);
+ if($this->_size!=='')
+ $writer->addStyleAttribute('font-size',$this->_size);
+ if($this->_name!=='')
+ $writer->addStyleAttribute('font-family',$this->_name);
+ }
+}
+class TStyle extends TComponent
+{
+ private $_fields=array();
+ private $_font=null;
+ private $_class=null;
+ private $_customStyle=null;
+ private $_displayStyle='Fixed';
+ public function __construct($style=null)
+ {
+ if($style!==null)
+ $this->copyFrom($style);
+ }
+ public function __clone()
+ {
+ if($this->_font!==null)
+ $this->_font = clone($this->_font);
+ }
+ public function getBackColor()
+ {
+ return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
+ }
+ public function setBackColor($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['background-color']);
+ else
+ $this->_fields['background-color']=$value;
+ }
+ public function getBorderColor()
+ {
+ return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
+ }
+ public function setBorderColor($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['border-color']);
+ else
+ $this->_fields['border-color']=$value;
+ }
+ public function getBorderStyle()
+ {
+ return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
+ }
+ public function setBorderStyle($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['border-style']);
+ else
+ $this->_fields['border-style']=$value;
+ }
+ public function getBorderWidth()
+ {
+ return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
+ }
+ public function setBorderWidth($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['border-width']);
+ else
+ $this->_fields['border-width']=$value;
+ }
+ public function getCssClass()
+ {
+ return $this->_class===null?'':$this->_class;
+ }
+ public function hasCssClass()
+ {
+ return ($this->_class!==null);
+ }
+ public function setCssClass($value)
+ {
+ $this->_class=$value;
+ }
+ public function getFont()
+ {
+ if($this->_font===null)
+ $this->_font=new TFont;
+ return $this->_font;
+ }
+ public function hasFont()
+ {
+ return $this->_font !== null;
+ }
+ public function setDisplayStyle($value)
+ {
+ $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
+ switch($this->_displayStyle)
+ {
+ case TDisplayStyle::None:
+ $this->_fields['display'] = 'none';
+ break;
+ case TDisplayStyle::Dynamic:
+ $this->_fields['display'] = ''; break;
+ case TDisplayStyle::Fixed:
+ $this->_fields['visibility'] = 'visible';
+ break;
+ case TDisplayStyle::Hidden:
+ $this->_fields['visibility'] = 'hidden';
+ break;
+ }
+ }
+ public function getDisplayStyle()
+ {
+ return $this->_displayStyle;
+ }
+ public function getForeColor()
+ {
+ return isset($this->_fields['color'])?$this->_fields['color']:'';
+ }
+ public function setForeColor($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['color']);
+ else
+ $this->_fields['color']=$value;
+ }
+ public function getHeight()
+ {
+ return isset($this->_fields['height'])?$this->_fields['height']:'';
+ }
+ public function setHeight($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['height']);
+ else
+ $this->_fields['height']=$value;
+ }
+ public function getCustomStyle()
+ {
+ return $this->_customStyle===null?'':$this->_customStyle;
+ }
+ public function setCustomStyle($value)
+ {
+ $this->_customStyle=$value;
+ }
+ public function getStyleField($name)
+ {
+ return isset($this->_fields[$name])?$this->_fields[$name]:'';
+ }
+ public function setStyleField($name,$value)
+ {
+ $this->_fields[$name]=$value;
+ }
+ public function clearStyleField($name)
+ {
+ unset($this->_fields[$name]);
+ }
+ public function hasStyleField($name)
+ {
+ return isset($this->_fields[$name]);
+ }
+ public function getWidth()
+ {
+ return isset($this->_fields['width'])?$this->_fields['width']:'';
+ }
+ public function setWidth($value)
+ {
+ $this->_fields['width']=$value;
+ }
+ public function reset()
+ {
+ $this->_fields=array();
+ $this->_font=null;
+ $this->_class=null;
+ $this->_customStyle=null;
+ }
+ public function copyFrom($style)
+ {
+ if($style instanceof TStyle)
+ {
+ $this->_fields=array_merge($this->_fields,$style->_fields);
+ if($style->_class!==null)
+ $this->_class=$style->_class;
+ if($style->_customStyle!==null)
+ $this->_customStyle=$style->_customStyle;
+ if($style->_font!==null)
+ $this->getFont()->copyFrom($style->_font);
+ }
+ }
+ public function mergeWith($style)
+ {
+ if($style instanceof TStyle)
+ {
+ $this->_fields=array_merge($style->_fields,$this->_fields);
+ if($this->_class===null)
+ $this->_class=$style->_class;
+ if($this->_customStyle===null)
+ $this->_customStyle=$style->_customStyle;
+ if($style->_font!==null)
+ $this->getFont()->mergeWith($style->_font);
+ }
+ }
+ public function addAttributesToRender($writer)
+ {
+ if($this->_customStyle!==null)
+ {
+ foreach(explode(';',$this->_customStyle) as $style)
+ {
+ $arr=explode(':',$style,2);
+ if(isset($arr[1]) && trim($arr[0])!=='')
+ $writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
+ }
+ }
+ $writer->addStyleAttributes($this->_fields);
+ if($this->_font!==null)
+ $this->_font->addAttributesToRender($writer);
+ if($this->_class!==null)
+ $writer->addAttribute('class',$this->_class);
+ }
+ public function getStyleFields()
+ {
+ return $this->_fields;
+ }
+}
+class TDisplayStyle extends TEnumerable
+{
+ const None='None';
+ const Dynamic='Dynamic';
+ const Fixed='Fixed';
+ const Hidden='Hidden';
+}
+class TTableStyle extends TStyle
+{
+ private $_backImageUrl=null;
+ private $_horizontalAlign=null;
+ private $_cellPadding=null;
+ private $_cellSpacing=null;
+ private $_gridLines=null;
+ private $_borderCollapse=null;
+ public function reset()
+ {
+ $this->_backImageUrl=null;
+ $this->_horizontalAlign=null;
+ $this->_cellPadding=null;
+ $this->_cellSpacing=null;
+ $this->_gridLines=null;
+ $this->_borderCollapse=null;
+ }
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TTableStyle)
+ {
+ if($style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($style->_cellPadding!==null)
+ $this->_cellPadding=$style->_cellPadding;
+ if($style->_cellSpacing!==null)
+ $this->_cellSpacing=$style->_cellSpacing;
+ if($style->_gridLines!==null)
+ $this->_gridLines=$style->_gridLines;
+ if($style->_borderCollapse!==null)
+ $this->_borderCollapse=$style->_borderCollapse;
+ }
+ }
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TTableStyle)
+ {
+ if($this->_backImageUrl===null && $style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($this->_cellPadding===null && $style->_cellPadding!==null)
+ $this->_cellPadding=$style->_cellPadding;
+ if($this->_cellSpacing===null && $style->_cellSpacing!==null)
+ $this->_cellSpacing=$style->_cellSpacing;
+ if($this->_gridLines===null && $style->_gridLines!==null)
+ $this->_gridLines=$style->_gridLines;
+ if($this->_borderCollapse===null && $style->_borderCollapse!==null)
+ $this->_borderCollapse=$style->_borderCollapse;
+ }
+ }
+ public function addAttributesToRender($writer)
+ {
+ if(($url=trim($this->getBackImageUrl()))!=='')
+ $writer->addStyleAttribute('background-image','url('.$url.')');
+ if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
+ $writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
+ if(($cellPadding=$this->getCellPadding())>=0)
+ $writer->addAttribute('cellpadding',"$cellPadding");
+ if(($cellSpacing=$this->getCellSpacing())>=0)
+ $writer->addAttribute('cellspacing',"$cellSpacing");
+ if($this->getBorderCollapse())
+ $writer->addStyleAttribute('border-collapse','collapse');
+ switch($this->getGridLines())
+ {
+ case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
+ case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
+ case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
+ }
+ parent::addAttributesToRender($writer);
+ }
+ public function getBackImageUrl()
+ {
+ return $this->_backImageUrl===null?'':$this->_backImageUrl;
+ }
+ public function setBackImageUrl($value)
+ {
+ $this->_backImageUrl=$value;
+ }
+ public function getHorizontalAlign()
+ {
+ return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
+ }
+ public function setHorizontalAlign($value)
+ {
+ $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
+ }
+ public function getCellPadding()
+ {
+ return $this->_cellPadding===null?-1:$this->_cellPadding;
+ }
+ public function setCellPadding($value)
+ {
+ if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
+ throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
+ }
+ public function getCellSpacing()
+ {
+ return $this->_cellSpacing===null?-1:$this->_cellSpacing;
+ }
+ public function setCellSpacing($value)
+ {
+ if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
+ throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
+ }
+ public function getGridLines()
+ {
+ return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
+ }
+ public function setGridLines($value)
+ {
+ $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
+ }
+ public function getBorderCollapse()
+ {
+ return $this->_borderCollapse===null?false:$this->_borderCollapse;
+ }
+ public function setBorderCollapse($value)
+ {
+ $this->_borderCollapse=TPropertyValue::ensureBoolean($value);
+ }
+}
+class TTableItemStyle extends TStyle
+{
+ private $_horizontalAlign=null;
+ private $_verticalAlign=null;
+ private $_wrap=null;
+ public function reset()
+ {
+ parent::reset();
+ $this->_verticalAlign=null;
+ $this->_horizontalAlign=null;
+ $this->_wrap=null;
+ }
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TTableItemStyle)
+ {
+ if($this->_verticalAlign===null && $style->_verticalAlign!==null)
+ $this->_verticalAlign=$style->_verticalAlign;
+ if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($this->_wrap===null && $style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TTableItemStyle)
+ {
+ if($style->_verticalAlign!==null)
+ $this->_verticalAlign=$style->_verticalAlign;
+ if($style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+ public function addAttributesToRender($writer)
+ {
+ if(!$this->getWrap())
+ $writer->addStyleAttribute('white-space','nowrap');
+ if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
+ $writer->addAttribute('align',strtolower($horizontalAlign));
+ if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
+ $writer->addAttribute('valign',strtolower($verticalAlign));
+ parent::addAttributesToRender($writer);
+ }
+ public function getHorizontalAlign()
+ {
+ return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
+ }
+ public function setHorizontalAlign($value)
+ {
+ $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
+ }
+ public function getVerticalAlign()
+ {
+ return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
+ }
+ public function setVerticalAlign($value)
+ {
+ $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
+ }
+ public function getWrap()
+ {
+ return $this->_wrap===null?true:$this->_wrap;
+ }
+ public function setWrap($value)
+ {
+ $this->_wrap=TPropertyValue::ensureBoolean($value);
+ }
+}
+class THorizontalAlign extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Left='Left';
+ const Right='Right';
+ const Center='Center';
+ const Justify='Justify';
+}
+class TVerticalAlign extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Top='Top';
+ const Bottom='Bottom';
+ const Middle='Middle';
+}
+class TTableGridLines extends TEnumerable
+{
+ const None='None';
+ const Horizontal='Horizontal';
+ const Vertical='Vertical';
+ const Both='Both';
+}
+class TWebControlAdapter extends TControlAdapter
+{
+ public function render($writer)
+ {
+ $this->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $this->renderEndTag($writer);
+ }
+ public function renderBeginTag($writer)
+ {
+ $this->getControl()->renderBeginTag($writer);
+ }
+ public function renderContents($writer)
+ {
+ $this->getControl()->renderContents($writer);
+ }
+ public function renderEndTag($writer)
+ {
+ $this->getControl()->renderEndTag($writer);
+ }
+}
+class TWebControlDecorator extends TComponent {
+ private $_internalonly;
+ private $_usestate = false;
+ private $_control;
+ private $_outercontrol;
+ private $_addedTemplateDecoration=false;
+ private $_pretagtext = '';
+ private $_precontentstext = '';
+ private $_postcontentstext = '';
+ private $_posttagtext = '';
+ private $_pretagtemplate;
+ private $_precontentstemplate;
+ private $_postcontentstemplate;
+ private $_posttagtemplate;
+ public function __construct($control, $onlyinternal = false) {
+ $this->_control = $control;
+ $this->_internalonly = $onlyinternal;
+ }
+ public function getUseState()
+ {
+ return $this->_usestate;
+ }
+ public function setUseState($value)
+ {
+ $this->_usestate = TPropertyValue::ensureBoolean($value);
+ }
+ public function getPreTagText() {
+ return $this->_pretagtext;
+ }
+ public function setPreTagText($value) {
+ if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
+ $this->_pretagtext = TPropertyValue::ensureString($value);
+ }
+ public function getPreContentsText() {
+ return $this->_precontentstext;
+ }
+ public function setPreContentsText($value) {
+ if(!$this->_control->getIsSkinApplied())
+ $this->_precontentstext = TPropertyValue::ensureString($value);
+ }
+ public function getPostContentsText() {
+ return $this->_postcontentstext;
+ }
+ public function setPostContentsText($value) {
+ if(!$this->_control->getIsSkinApplied())
+ $this->_postcontentstext = TPropertyValue::ensureString($value);
+ }
+ public function getPostTagText() {
+ return $this->_posttagtext;
+ }
+ public function setPostTagText($value) {
+ if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
+ $this->_posttagtext = TPropertyValue::ensureString($value);
+ }
+ public function getPreTagTemplate() {
+ return $this->_pretagtemplate;
+ }
+ public function setPreTagTemplate($value) {
+ if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
+ $this->_pretagtemplate = $value;
+ }
+ public function getPreContentsTemplate() {
+ return $this->_precontentstemplate;
+ }
+ public function setPreContentsTemplate($value) {
+ if(!$this->_control->getIsSkinApplied())
+ $this->_precontentstemplate = $value;
+ }
+ public function getPostContentsTemplate() {
+ return $this->_postcontentstemplate;
+ }
+ public function setPostContentsTemplate($value) {
+ if(!$this->_control->getIsSkinApplied())
+ $this->_postcontentstemplate = $value;
+ }
+ public function getPostTagTemplate() {
+ return $this->_posttagtemplate;
+ }
+ public function setPostTagTemplate($value) {
+ if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
+ $this->_posttagtemplate = $value;
+ }
+ public function instantiate($outercontrol = null) {
+ if($this->getPreTagTemplate() || $this->getPreContentsTemplate() ||
+ $this->getPostContentsTemplate() || $this->getPostTagTemplate()) {
+ $this->_outercontrol = $outercontrol;
+ if($this->getUseState())
+ $this->ensureTemplateDecoration();
+ else
+ $this->_control->getPage()->onSaveStateComplete[] = array($this, 'ensureTemplateDecoration');
+ }
+ }
+ public function ensureTemplateDecoration($sender=null, $param=null) {
+ $control = $this->_control;
+ $outercontrol = $this->_outercontrol;
+ if($outercontrol === null)
+ $outercontrol = $control;
+ if($this->_addedTemplateDecoration)
+ return $this->_addedTemplateDecoration;
+ $this->_addedTemplateDecoration = true;
+ if($this->getPreContentsTemplate())
+ {
+ $precontents = Prado::createComponent('TCompositeControl');
+ $this->getPreContentsTemplate()->instantiateIn($precontents);
+ $control->getControls()->insertAt(0, $precontents);
+ }
+ if($this->getPostContentsTemplate())
+ {
+ $postcontents = Prado::createComponent('TCompositeControl');
+ $this->getPostContentsTemplate()->instantiateIn($postcontents);
+ $control->getControls()->add($postcontents);
+ }
+ if(!$outercontrol->getParent())
+ return $this->_addedTemplateDecoration;
+ if($this->getPreTagTemplate())
+ {
+ $pretag = Prado::createComponent('TCompositeControl');
+ $this->getPreTagTemplate()->instantiateIn($pretag);
+ $outercontrol->getParent()->getControls()->insertBefore($outercontrol, $pretag);
+ }
+ if($this->getPostTagTemplate())
+ {
+ $posttag = Prado::createComponent('TCompositeControl');
+ $this->getPostTagTemplate()->instantiateIn($posttag);
+ $outercontrol->getParent()->getControls()->insertAfter($outercontrol, $posttag);
+ }
+ return true;
+ }
+ public function renderPreTagText($writer) {
+ $writer->write($this->getPreTagText());
+ }
+ public function renderPreContentsText($writer) {
+ $writer->write($this->getPreContentsText());
+ }
+ public function renderPostContentsText($writer) {
+ $writer->write($this->getPostContentsText());
+ }
+ public function renderPostTagText($writer) {
+ $writer->write($this->getPostTagText());
+ }
+}
+class TWebControl extends TControl implements IStyleable
+{
+ private $_ensureid=false;
+ protected $_decorator;
+ public function setEnsureId($value)
+ {
+ $this->_ensureid |= TPropertyValue::ensureBoolean($value);
+ }
+ public function getEnsureId()
+ {
+ return $this->_ensureid;
+ }
+ public function getDecorator($create=true)
+ {
+ if($create && !$this->_decorator)
+ $this->_decorator = Prado::createComponent('TWebControlDecorator', $this);
+ return $this->_decorator;
+ }
+ public function copyBaseAttributes(TWebControl $control)
+ {
+ $this->setAccessKey($control->getAccessKey());
+ $this->setToolTip($control->getToolTip());
+ $this->setTabIndex($control->getTabIndex());
+ if(!$control->getEnabled())
+ $this->setEnabled(false);
+ if($control->getHasAttributes())
+ $this->getAttributes()->copyFrom($control->getAttributes());
+ }
+ public function getAccessKey()
+ {
+ return $this->getViewState('AccessKey','');
+ }
+ public function setAccessKey($value)
+ {
+ if(strlen($value)>1)
+ throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
+ $this->setViewState('AccessKey',$value,'');
+ }
+ public function getBackColor()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getBackColor();
+ else
+ return '';
+ }
+ public function setBackColor($value)
+ {
+ $this->getStyle()->setBackColor($value);
+ }
+ public function getBorderColor()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getBorderColor();
+ else
+ return '';
+ }
+ public function setBorderColor($value)
+ {
+ $this->getStyle()->setBorderColor($value);
+ }
+ public function getBorderStyle()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getBorderStyle();
+ else
+ return '';
+ }
+ public function setBorderStyle($value)
+ {
+ $this->getStyle()->setBorderStyle($value);
+ }
+ public function getBorderWidth()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getBorderWidth();
+ else
+ return '';
+ }
+ public function setBorderWidth($value)
+ {
+ $this->getStyle()->setBorderWidth($value);
+ }
+ public function getFont()
+ {
+ return $this->getStyle()->getFont();
+ }
+ public function getForeColor()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getForeColor();
+ else
+ return '';
+ }
+ public function setForeColor($value)
+ {
+ $this->getStyle()->setForeColor($value);
+ }
+ public function getHeight()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getHeight();
+ else
+ return '';
+ }
+ public function setDisplay($value)
+ {
+ $this->getStyle()->setDisplayStyle($value);
+ }
+ public function getDisplay()
+ {
+ return $this->getStyle()->getDisplayStyle();
+ }
+ public function setCssClass($value)
+ {
+ $this->getStyle()->setCssClass($value);
+ }
+ public function getCssClass()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getCssClass();
+ else
+ return '';
+ }
+ public function setHeight($value)
+ {
+ $this->getStyle()->setHeight($value);
+ }
+ public function getHasStyle()
+ {
+ return $this->getViewState('Style',null)!==null;
+ }
+ protected function createStyle()
+ {
+ return new TStyle;
+ }
+ public function getStyle()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style;
+ else
+ {
+ $style=$this->createStyle();
+ $this->setViewState('Style',$style,null);
+ return $style;
+ }
+ }
+ public function setStyle($value)
+ {
+ if(is_string($value))
+ $this->getStyle()->setCustomStyle($value);
+ else
+ throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
+ }
+ public function clearStyle()
+ {
+ $this->clearViewState('Style');
+ }
+ public function getTabIndex()
+ {
+ return $this->getViewState('TabIndex',0);
+ }
+ public function setTabIndex($value)
+ {
+ $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
+ }
+ protected function getTagName()
+ {
+ return 'span';
+ }
+ public function getToolTip()
+ {
+ return $this->getViewState('ToolTip','');
+ }
+ public function setToolTip($value)
+ {
+ $this->setViewState('ToolTip',$value,'');
+ }
+ public function getWidth()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getWidth();
+ else
+ return '';
+ }
+ public function setWidth($value)
+ {
+ $this->getStyle()->setWidth($value);
+ }
+ public function onPreRender($param) {
+ if($decorator = $this->getDecorator(false))
+ $decorator->instantiate();
+ parent::onPreRender($param);
+ }
+ protected function addAttributesToRender($writer)
+ {
+ if($this->getID()!=='' || $this->getEnsureId())
+ $writer->addAttribute('id',$this->getClientID());
+ if(($accessKey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accessKey);
+ if(!$this->getEnabled())
+ $writer->addAttribute('disabled','disabled');
+ if(($tabIndex=$this->getTabIndex())>0)
+ $writer->addAttribute('tabindex',"$tabIndex");
+ if(($toolTip=$this->getToolTip())!=='')
+ $writer->addAttribute('title',$toolTip);
+ if($style=$this->getViewState('Style',null))
+ $style->addAttributesToRender($writer);
+ if($this->getHasAttributes())
+ {
+ foreach($this->getAttributes() as $name=>$value)
+ $writer->addAttribute($name,$value);
+ }
+ }
+ public function render($writer)
+ {
+ $this->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $this->renderEndTag($writer);
+ }
+ public function renderBeginTag($writer)
+ {
+ if($decorator = $this->getDecorator(false)) {
+ $decorator->renderPreTagText($writer);
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag($this->getTagName());
+ $decorator->renderPreContentsText($writer);
+ } else {
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag($this->getTagName());
+ }
+ }
+ public function renderContents($writer)
+ {
+ parent::renderChildren($writer);
+ }
+ public function renderEndTag($writer)
+ {
+ if($decorator = $this->getDecorator(false)) {
+ $decorator->renderPostContentsText($writer);
+ $writer->renderEndTag();
+ $decorator->renderPostTagText($writer);
+ } else
+ $writer->renderEndTag($writer);
+ }
+}
+class TCompositeControl extends TControl implements INamingContainer
+{
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ parent::initRecursive($namingContainer);
+ }
+}
+class TTemplateControl extends TCompositeControl
+{
+ const EXT_TEMPLATE='.tpl';
+ private static $_template=array();
+ private $_localTemplate=null;
+ private $_master=null;
+ private $_masterClass='';
+ private $_contents=array();
+ private $_placeholders=array();
+ public function getTemplate()
+ {
+ if($this->_localTemplate===null)
+ {
+ $class=get_class($this);
+ if(!isset(self::$_template[$class]))
+ self::$_template[$class]=$this->loadTemplate();
+ return self::$_template[$class];
+ }
+ else
+ return $this->_localTemplate;
+ }
+ public function setTemplate($value)
+ {
+ $this->_localTemplate=$value;
+ }
+ public function getIsSourceTemplateControl()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getIsSourceTemplate();
+ else
+ return false;
+ }
+ public function getTemplateDirectory()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getContextPath();
+ else
+ return '';
+ }
+ protected function loadTemplate()
+ {
+ $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
+ return $template;
+ }
+ public function createChildControls()
+ {
+ if($tpl=$this->getTemplate())
+ {
+ foreach($tpl->getDirective() as $name=>$value)
+ {
+ if(is_string($value))
+ $this->setSubProperty($name,$value);
+ else
+ throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
+ }
+ $tpl->instantiateIn($this);
+ }
+ }
+ public function registerContent($id,TContent $object)
+ {
+ if(isset($this->_contents[$id]))
+ throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
+ else
+ $this->_contents[$id]=$object;
+ }
+ public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
+ {
+ if(isset($this->_placeholders[$id]))
+ throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
+ else
+ $this->_placeholders[$id]=$object;
+ }
+ public function getMasterClass()
+ {
+ return $this->_masterClass;
+ }
+ public function setMasterClass($value)
+ {
+ $this->_masterClass=$value;
+ }
+ public function getMaster()
+ {
+ return $this->_master;
+ }
+ public function injectContent($id,$content)
+ {
+ if(isset($this->_placeholders[$id]))
+ {
+ $placeholder=$this->_placeholders[$id];
+ $controls=$placeholder->getParent()->getControls();
+ $loc=$controls->remove($placeholder);
+ $controls->insertAt($loc,$content);
+ }
+ else
+ throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
+ }
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ if($this->_masterClass!=='')
+ {
+ $master=Prado::createComponent($this->_masterClass);
+ if(!($master instanceof TTemplateControl))
+ throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
+ $this->_master=$master;
+ $this->getControls()->clear();
+ $this->getControls()->add($master);
+ $master->ensureChildControls();
+ foreach($this->_contents as $id=>$content)
+ $master->injectContent($id,$content);
+ }
+ else if(!empty($this->_contents))
+ throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
+ parent::initRecursive($namingContainer);
+ }
+ public function tryToUpdateView($arObj, $throwExceptions = false)
+ {
+ $objAttrs = get_class_vars(get_class($arObj));
+ foreach (array_keys($objAttrs) as $key)
+ {
+ try
+ {
+ if ($key != "RELATIONS")
+ {
+ $control = $this->{$key};
+ if ($control instanceof TTextBox)
+ $control->Text = $arObj->{$key};
+ elseif ($control instanceof TCheckBox)
+ $control->Checked = (boolean) $arObj->{$key};
+ elseif ($control instanceof TDatePicker)
+ $control->Date = $arObj->{$key};
+ }
+ else
+ {
+ foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
+ {
+ $relControl = $this->{$relKey};
+ switch ($relValues[0])
+ {
+ case TActiveRecord::BELONGS_TO:
+ case TActiveRecord::HAS_ONE:
+ $relControl->Text = $arObj->{$relKey};
+ break;
+ case TActiveRecord::HAS_MANY:
+ if ($relControl instanceof TListControl)
+ {
+ $relControl->DataSource = $arObj->{$relKey};
+ $relControl->dataBind();
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ catch (Exception $ex)
+ {
+ if ($throwExceptions)
+ throw $ex;
+ }
+ }
+ }
+ public function tryToUpdateAR($arObj, $throwExceptions = false)
+ {
+ $objAttrs = get_class_vars(get_class($arObj));
+ foreach (array_keys($objAttrs) as $key)
+ {
+ try
+ {
+ if ($key == "RELATIONS")
+ break;
+ $control = $this->{$key};
+ if ($control instanceof TTextBox)
+ $arObj->{$key} = $control->Text;
+ elseif ($control instanceof TCheckBox)
+ $arObj->{$key} = $control->Checked;
+ elseif ($control instanceof TDatePicker)
+ $arObj->{$key} = $control->Date;
+ }
+ catch (Exception $ex)
+ {
+ if ($throwExceptions)
+ throw $ex;
+ }
+ }
+ }
+}
+class TForm extends TControl
+{
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->getPage()->setForm($this);
+ }
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $writer->addAttribute('method',$this->getMethod());
+ $uri=$this->getRequest()->getRequestURI();
+ $writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
+ if(($enctype=$this->getEnctype())!=='')
+ $writer->addAttribute('enctype',$enctype);
+ $attributes=$this->getAttributes();
+ $attributes->remove('action');
+ $writer->addAttributes($attributes);
+ if(($butt=$this->getDefaultButton())!=='')
+ {
+ if(($button=$this->findControl($butt))!==null)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ else
+ throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
+ }
+ }
+ public function render($writer)
+ {
+ $page=$this->getPage();
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag('form');
+ $cs=$page->getClientScript();
+ if($page->getClientSupportsJavaScript())
+ {
+ $cs->renderHiddenFieldsBegin($writer);
+ $cs->renderScriptFilesBegin($writer);
+ $cs->renderBeginScripts($writer);
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $cs->renderHiddenFieldsEnd($writer);
+ $page->endFormRender($writer);
+ $cs->renderScriptFilesEnd($writer);
+ $cs->renderEndScripts($writer);
+ }
+ else
+ {
+ $cs->renderHiddenFieldsBegin($writer);
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $page->endFormRender($writer);
+ $cs->renderHiddenFieldsEnd($writer);
+ }
+ $writer->renderEndTag();
+ }
+ public function getDefaultButton()
+ {
+ return $this->getViewState('DefaultButton','');
+ }
+ public function setDefaultButton($value)
+ {
+ $this->setViewState('DefaultButton',$value,'');
+ }
+ public function getMethod()
+ {
+ return $this->getViewState('Method','post');
+ }
+ public function setMethod($value)
+ {
+ $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
+ }
+ public function getEnctype()
+ {
+ return $this->getViewState('Enctype','');
+ }
+ public function setEnctype($value)
+ {
+ $this->setViewState('Enctype',$value,'');
+ }
+ public function getName()
+ {
+ return $this->getUniqueID();
+ }
+}
+class TClientScriptManager extends TApplicationComponent
+{
+ const SCRIPT_PATH='Web/Javascripts/source';
+ const PACKAGES_FILE='Web/Javascripts/packages.php';
+ private $_page;
+ private $_hiddenFields=array();
+ private $_beginScripts=array();
+ private $_endScripts=array();
+ private $_scriptFiles=array();
+ private $_headScriptFiles=array();
+ private $_headScripts=array();
+ private $_styleSheetFiles=array();
+ private $_styleSheets=array();
+ private $_registeredPradoScripts=array();
+ private static $_pradoScripts;
+ private static $_pradoPackages;
+ private $_renderedHiddenFields;
+ private $_renderedScriptFiles=array();
+ private $_expandedPradoScripts;
+ public function __construct(TPage $owner)
+ {
+ $this->_page=$owner;
+ }
+ public function getRequiresHead()
+ {
+ return count($this->_styleSheetFiles) || count($this->_styleSheets)
+ || count($this->_headScriptFiles) || count($this->_headScripts);
+ }
+ public static function getPradoPackages()
+ {
+ return self::$_pradoPackages;
+ }
+ public static function getPradoScripts()
+ {
+ return self::$_pradoScripts;
+ }
+ public function registerPradoScript($name)
+ {
+ $this->registerPradoScriptInternal($name);
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
+ }
+ protected function registerPradoScriptInternal($name)
+ {
+ if(!isset($this->_registeredPradoScripts[$name]))
+ {
+ if(self::$_pradoScripts === null)
+ {
+ $packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::PACKAGES_FILE;
+ list($packages,$deps)= include($packageFile);
+ self::$_pradoScripts = $deps;
+ self::$_pradoPackages = $packages;
+ }
+ if (isset(self::$_pradoScripts[$name]))
+ $this->_registeredPradoScripts[$name]=true;
+ else
+ throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
+ if(($packages=array_keys($this->_registeredPradoScripts))!==array())
+ {
+ $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
+ list($path,$baseUrl)=$this->getPackagePathUrl($base);
+ $packagesUrl=array();
+ $isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
+ foreach ($packages as $p)
+ {
+ foreach (self::$_pradoScripts[$p] as $dep)
+ {
+ foreach (self::$_pradoPackages[$dep] as $script)
+ if (!isset($this->_expandedPradoScripts[$script]))
+ {
+ $this->_expandedPradoScripts[$script] = true;
+ if($isDebug)
+ {
+ if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
+ $packagesUrl[]=$url;
+ } else {
+ if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))
+ {
+ if(!is_file($filePath=$path.'/min/'.$script))
+ {
+ $dirPath=dirname($filePath);
+ if(!is_dir($dirPath))
+ mkdir($dirPath, PRADO_CHMOD, true);
+ file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script)));
+ chmod($filePath, PRADO_CHMOD);
+ }
+ $packagesUrl[]=$url;
+ }
+ }
+ }
+ }
+ }
+ foreach($packagesUrl as $url)
+ $this->registerScriptFile($url,$url);
+ }
+ }
+ }
+ public function getPradoScriptAssetUrl()
+ {
+ $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
+ $assets = Prado::getApplication()->getAssetManager();
+ return $assets->getPublishedUrl($base);
+ }
+ public function getScriptUrls()
+ {
+ $scripts = array_values($this->_headScriptFiles);
+ $scripts = array_merge($scripts, array_values($this->_scriptFiles));
+ $scripts = array_unique($scripts);
+ return $scripts;
+ }
+ protected function getPackagePathUrl($base)
+ {
+ $assets = Prado::getApplication()->getAssetManager();
+ if(strpos($base, $assets->getBaseUrl())===false)
+ {
+ if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
+ $base = $dir;
+ }
+ return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
+ }
+ else
+ {
+ return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
+ }
+ }
+ public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
+ {
+ $options = !is_array($options) ? array() : $options;
+ $class = new ReflectionClass($callbackHandler);
+ $clientSide = $callbackHandler->getActiveControl()->getClientSide();
+ $options = array_merge($options, $clientSide->getOptions()->toArray());
+ $optionString = TJavaScript::encode($options);
+ $this->registerPradoScriptInternal('ajax');
+ $id = $callbackHandler->getUniqueID();
+ return "new Prado.CallbackRequest('{$id}',{$optionString})";
+ }
+ public function registerCallbackControl($class, $options)
+ {
+ $optionString=TJavaScript::encode($options);
+ $code="new {$class}({$optionString});";
+ $this->_endScripts[sprintf('%08X', crc32($code))]=$code;
+ $this->registerPradoScriptInternal('ajax');
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
+ }
+ public function registerPostBackControl($class,$options)
+ {
+ if($class === null) {
+ return;
+ }
+ if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
+ $options['FormID']=$form->getClientID();
+ $optionString=TJavaScript::encode($options);
+ $code="new {$class}({$optionString});";
+ $this->_endScripts[sprintf('%08X', crc32($code))]=$code;
+ $this->registerPradoScriptInternal('prado');
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
+ }
+ public function registerDefaultButton($panel, $button)
+ {
+ $panelID=is_string($panel)?$panel:$panel->getUniqueID();
+ if(is_string($button))
+ $buttonID=$button;
+ else
+ {
+ $button->setIsDefaultButton(true);
+ $buttonID=$button->getUniqueID();
+ }
+ $options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
+ $code = "new Prado.WebUI.DefaultButton($options);";
+ $this->_endScripts['prado:'.$panelID]=$code;
+ $this->registerPradoScriptInternal('prado');
+ $params=array($panelID,$buttonID);
+ $this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
+ }
+ protected function getDefaultButtonOptions($panelID, $buttonID)
+ {
+ $options['ID'] = TControl::convertUniqueIdToClientId($panelID);
+ $options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
+ $options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
+ $options['EventTarget'] = $buttonID;
+ $options['Event'] = 'click';
+ return $options;
+ }
+ public function registerFocusControl($target)
+ {
+ $this->registerPradoScriptInternal('jquery');
+ if($target instanceof TControl)
+ $target=$target->getClientID();
+ $this->_endScripts['prado:focus'] = 'jQuery(\'#'.$target.'\').focus();';
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
+ }
+ public function registerStyleSheetFile($key,$url,$media='')
+ {
+ if($media==='')
+ $this->_styleSheetFiles[$key]=$url;
+ else
+ $this->_styleSheetFiles[$key]=array($url,$media);
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
+ }
+ public function registerStyleSheet($key,$css,$media='')
+ {
+ $this->_styleSheets[$key]=$css;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
+ }
+ public function getStyleSheetUrls()
+ {
+ $stylesheets = array_values(
+ array_map(
+ create_function('$e', 'return is_array($e) ? $e[0] : $e;'),
+ $this->_styleSheetFiles)
+ );
+ foreach(Prado::getApplication()->getAssetManager()->getPublished() as $path=>$url)
+ if (substr($url,strlen($url)-4)=='.css')
+ $stylesheets[] = $url;
+ $stylesheets = array_unique($stylesheets);
+ return $stylesheets;
+ }
+ public function getStyleSheetCodes()
+ {
+ return array_unique(array_values($this->_styleSheets));
+ }
+ public function registerHeadScriptFile($key,$url)
+ {
+ $this->checkIfNotInRender();
+ $this->_headScriptFiles[$key]=$url;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
+ }
+ public function registerHeadScript($key,$script)
+ {
+ $this->checkIfNotInRender();
+ $this->_headScripts[$key]=$script;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
+ }
+ public function registerScriptFile($key, $url)
+ {
+ $this->_scriptFiles[$key]=$url;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
+ }
+ public function registerBeginScript($key,$script)
+ {
+ $this->checkIfNotInRender();
+ $this->_beginScripts[$key]=$script;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
+ }
+ public function registerEndScript($key,$script)
+ {
+ $this->_endScripts[$key]=$script;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
+ }
+ public function registerHiddenField($name,$value)
+ {
+ $this->_hiddenFields[$name]=$value;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
+ }
+ public function isStyleSheetFileRegistered($key)
+ {
+ return isset($this->_styleSheetFiles[$key]);
+ }
+ public function isStyleSheetRegistered($key)
+ {
+ return isset($this->_styleSheets[$key]);
+ }
+ public function isHeadScriptFileRegistered($key)
+ {
+ return isset($this->_headScriptFiles[$key]);
+ }
+ public function isHeadScriptRegistered($key)
+ {
+ return isset($this->_headScripts[$key]);
+ }
+ public function isScriptFileRegistered($key)
+ {
+ return isset($this->_scriptFiles[$key]);
+ }
+ public function isBeginScriptRegistered($key)
+ {
+ return isset($this->_beginScripts[$key]);
+ }
+ public function isEndScriptRegistered($key)
+ {
+ return isset($this->_endScripts[$key]);
+ }
+ public function hasEndScripts()
+ {
+ return count($this->_endScripts) > 0;
+ }
+ public function hasBeginScripts()
+ {
+ return count($this->_beginScripts) > 0;
+ }
+ public function isHiddenFieldRegistered($key)
+ {
+ return isset($this->_hiddenFields[$key]);
+ }
+ public function renderStyleSheetFiles($writer)
+ {
+ $str='';
+ foreach($this->_styleSheetFiles as $url)
+ {
+ if(is_array($url))
+ $str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
+ else
+ $str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
+ }
+ $writer->write($str);
+ }
+ public function renderStyleSheets($writer)
+ {
+ if(count($this->_styleSheets))
+ $writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
+ }
+ public function renderHeadScriptFiles($writer)
+ {
+ $this->renderScriptFiles($writer,$this->_headScriptFiles);
+ }
+ public function renderHeadScripts($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
+ }
+ public function renderScriptFilesBegin($writer)
+ {
+ $this->renderAllPendingScriptFiles($writer);
+ }
+ public function renderScriptFilesEnd($writer)
+ {
+ $this->renderAllPendingScriptFiles($writer);
+ }
+ public function markScriptFileAsRendered($url)
+ {
+ $this->_renderedScriptFiles[$url] = $url;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','markScriptFileAsRendered',$params);
+ }
+ protected function renderScriptFiles($writer, Array $scripts)
+ {
+ foreach($scripts as $script)
+ {
+ $writer->write(TJavaScript::renderScriptFile($script));
+ $this->markScriptFileAsRendered($script);
+ }
+ }
+ protected function getRenderedScriptFiles()
+ {
+ return $this->_renderedScriptFiles;
+ }
+ public function renderAllPendingScriptFiles($writer)
+ {
+ if(!empty($this->_scriptFiles))
+ {
+ $addedScripts = array_diff($this->_scriptFiles,$this->getRenderedScriptFiles());
+ $this->renderScriptFiles($writer,$addedScripts);
+ }
+ }
+ public function renderBeginScripts($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
+ }
+ public function renderEndScripts($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
+ }
+ public function renderBeginScriptsCallback($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocksCallback($this->_beginScripts));
+ }
+ public function renderEndScriptsCallback($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocksCallback($this->_endScripts));
+ }
+ public function renderHiddenFieldsBegin($writer)
+ {
+ $this->renderHiddenFieldsInt($writer,true);
+ }
+ public function renderHiddenFieldsEnd($writer)
+ {
+ $this->renderHiddenFieldsInt($writer,false);
+ }
+ public function flushScriptFiles($writer, $control=null)
+ {
+ if(!$this->_page->getIsCallback())
+ {
+ $this->_page->ensureRenderInForm($control);
+ $this->renderAllPendingScriptFiles($writer);
+ }
+ }
+ protected function renderHiddenFieldsInt($writer, $initial)
+ {
+ if ($initial) $this->_renderedHiddenFields = array();
+ $str='';
+ foreach($this->_hiddenFields as $name=>$value)
+ {
+ if (in_array($name,$this->_renderedHiddenFields)) continue;
+ $id=strtr($name,':','_');
+ if(is_array($value))
+ {
+ foreach($value as $v)
+ $str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
+ }
+ else
+ {
+ $str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
+ }
+ $this->_renderedHiddenFields[] = $name;
+ }
+ if($str!=='')
+ $writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
+ }
+ public function getHiddenFields()
+ {
+ return $this->_hiddenFields;
+ }
+ protected function checkIfNotInRender()
+ {
+ if ($form = $this->_page->InFormRender)
+ throw new Exception('Operation invalid when page is already rendering');
+ }
+}
+abstract class TClientSideOptions extends TComponent
+{
+ private $_options;
+ protected function setFunction($name, $code)
+ {
+ if(!TJavaScript::isJsLiteral($code))
+ $code = TJavaScript::quoteJsLiteral($this->ensureFunction($code));
+ $this->setOption($name, $code);
+ }
+ protected function getOption($name)
+ {
+ if ($this->_options)
+ return $this->_options->itemAt($name);
+ else
+ return null;
+ }
+ protected function setOption($name, $value)
+ {
+ $this->getOptions()->add($name, $value);
+ }
+ public function getOptions()
+ {
+ if (!$this->_options)
+ $this->_options = Prado::createComponent('System.Collections.TMap');
+ return $this->_options;
+ }
+ protected function ensureFunction($javascript)
+ {
+ return "function(sender, parameter){ {$javascript} }";
+ }
+}
+class TPage extends TTemplateControl
+{
+ const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
+ const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
+ const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
+ const FIELD_PAGESTATE='PRADO_PAGESTATE';
+ const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
+ const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
+ private static $_systemPostFields=array(
+ 'PRADO_POSTBACK_TARGET'=>true,
+ 'PRADO_POSTBACK_PARAMETER'=>true,
+ 'PRADO_LASTFOCUS'=>true,
+ 'PRADO_PAGESTATE'=>true,
+ 'PRADO_CALLBACK_TARGET'=>true,
+ 'PRADO_CALLBACK_PARAMETER'=>true
+ );
+ private $_form;
+ private $_head;
+ private $_validators=array();
+ private $_validated=false;
+ private $_theme;
+ private $_title;
+ private $_styleSheet;
+ private $_clientScript;
+ protected $_postData;
+ protected $_restPostData;
+ protected $_controlsPostDataChanged=array();
+ protected $_controlsRequiringPostData=array();
+ protected $_controlsRegisteredForPostData=array();
+ private $_postBackEventTarget;
+ private $_postBackEventParameter;
+ protected $_formRendered=false;
+ protected $_inFormRender=false;
+ private $_focus;
+ private $_pagePath='';
+ private $_enableStateValidation=true;
+ private $_enableStateEncryption=false;
+ private $_enableStateCompression=true;
+ private $_statePersisterClass='System.Web.UI.TPageStatePersister';
+ private $_statePersister;
+ private $_cachingStack;
+ private $_clientState='';
+ protected $_isLoadingPostData=false;
+ private $_enableJavaScript=true;
+ private $_writer;
+ public function __construct()
+ {
+ $this->setPage($this);
+ }
+ public function run($writer)
+ {
+ $this->_writer = $writer;
+ $this->determinePostBackMode();
+ if($this->getIsPostBack())
+ {
+ if($this->getIsCallback())
+ $this->processCallbackRequest($writer);
+ else
+ $this->processPostBackRequest($writer);
+ }
+ else
+ $this->processNormalRequest($writer);
+ $this->_writer = null;
+ }
+ protected function processNormalRequest($writer)
+ {
+ $this->onPreInit(null);
+ $this->initRecursive();
+ $this->onInitComplete(null);
+ $this->onPreLoad(null);
+ $this->loadRecursive();
+ $this->onLoadComplete(null);
+ $this->preRenderRecursive();
+ $this->onPreRenderComplete(null);
+ $this->savePageState();
+ $this->onSaveStateComplete(null);
+ $this->renderControl($writer);
+ $this->unloadRecursive();
+ }
+ protected function processPostBackRequest($writer)
+ {
+ $this->onPreInit(null);
+ $this->initRecursive();
+ $this->onInitComplete(null);
+ $this->_restPostData=new TMap;
+ $this->loadPageState();
+ $this->processPostData($this->_postData,true);
+ $this->onPreLoad(null);
+ $this->loadRecursive();
+ $this->processPostData($this->_restPostData,false);
+ $this->raiseChangedEvents();
+ $this->raisePostBackEvent();
+ $this->onLoadComplete(null);
+ $this->preRenderRecursive();
+ $this->onPreRenderComplete(null);
+ $this->savePageState();
+ $this->onSaveStateComplete(null);
+ $this->renderControl($writer);
+ $this->unloadRecursive();
+ }
+ protected static function decodeUTF8($data, $enc)
+ {
+ if(is_array($data))
+ {
+ foreach($data as $k=>$v)
+ $data[$k]=self::decodeUTF8($v, $enc);
+ return $data;
+ } elseif(is_string($data)) {
+ return iconv('UTF-8',$enc.'//IGNORE',$data);
+ } else {
+ return $data;
+ }
+ }
+ protected function processCallbackRequest($writer)
+ {
+ Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
+ $this->setAdapter(new TActivePageAdapter($this));
+ $callbackEventParameter = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
+ if(strlen($callbackEventParameter) > 0)
+ $this->_postData[TPage::FIELD_CALLBACK_PARAMETER]=TJavaScript::jsonDecode((string)$callbackEventParameter);
+ if (($g=$this->getApplication()->getGlobalization(false))!==null &&
+ strtoupper($enc=$g->getCharset())!='UTF-8')
+ foreach ($this->_postData as $k=>$v)
+ $this->_postData[$k]=self::decodeUTF8($v, $enc);
+ $this->onPreInit(null);
+ $this->initRecursive();
+ $this->onInitComplete(null);
+ $this->_restPostData=new TMap;
+ $this->loadPageState();
+ $this->processPostData($this->_postData,true);
+ $this->onPreLoad(null);
+ $this->loadRecursive();
+ $this->processPostData($this->_restPostData,false);
+ $this->raiseChangedEvents();
+ $this->getAdapter()->processCallbackEvent($writer);
+ $this->onLoadComplete(null);
+ $this->preRenderRecursive();
+ $this->onPreRenderComplete(null);
+ $this->savePageState();
+ $this->onSaveStateComplete(null);
+ $this->getAdapter()->renderCallbackResponse($writer);
+ $this->unloadRecursive();
+ }
+ public function getCallbackClient()
+ {
+ if($this->getAdapter() !== null)
+ return $this->getAdapter()->getCallbackClientHandler();
+ else
+ return new TCallbackClientScript();
+ }
+ public function setCallbackClient($client)
+ {
+ $this->getAdapter()->setCallbackClientHandler($client);
+ }
+ public function getCallbackEventTarget()
+ {
+ return $this->getAdapter()->getCallbackEventTarget();
+ }
+ public function setCallbackEventTarget(TControl $control)
+ {
+ $this->getAdapter()->setCallbackEventTarget($control);
+ }
+ public function getCallbackEventParameter()
+ {
+ return $this->getAdapter()->getCallbackEventParameter();
+ }
+ public function setCallbackEventParameter($value)
+ {
+ $this->getAdapter()->setCallbackEventParameter($value);
+ }
+ public function getForm()
+ {
+ return $this->_form;
+ }
+ public function setForm(TForm $form)
+ {
+ if($this->_form===null)
+ $this->_form=$form;
+ else
+ throw new TInvalidOperationException('page_form_duplicated');
+ }
+ public function getValidators($validationGroup=null)
+ {
+ if(!$this->_validators)
+ $this->_validators=new TList;
+ if(empty($validationGroup) === true)
+ return $this->_validators;
+ else
+ {
+ $list=new TList;
+ foreach($this->_validators as $validator)
+ if($validator->getValidationGroup()===$validationGroup)
+ $list->add($validator);
+ return $list;
+ }
+ }
+ public function validate($validationGroup=null)
+ {
+ $this->_validated=true;
+ if($this->_validators && $this->_validators->getCount())
+ {
+ if($validationGroup===null)
+ {
+ foreach($this->_validators as $validator)
+ $validator->validate();
+ }
+ else
+ {
+ foreach($this->_validators as $validator)
+ {
+ if($validator->getValidationGroup()===$validationGroup)
+ $validator->validate();
+ }
+ }
+ }
+ }
+ public function getIsValid()
+ {
+ if($this->_validated)
+ {
+ if($this->_validators && $this->_validators->getCount())
+ {
+ foreach($this->_validators as $validator)
+ if(!$validator->getIsValid())
+ return false;
+ }
+ return true;
+ }
+ else
+ throw new TInvalidOperationException('page_isvalid_unknown');
+ }
+ public function getTheme()
+ {
+ if(is_string($this->_theme))
+ $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
+ return $this->_theme;
+ }
+ public function setTheme($value)
+ {
+ $this->_theme=empty($value)?null:$value;
+ }
+ public function getStyleSheetTheme()
+ {
+ if(is_string($this->_styleSheet))
+ $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
+ return $this->_styleSheet;
+ }
+ public function setStyleSheetTheme($value)
+ {
+ $this->_styleSheet=empty($value)?null:$value;
+ }
+ public function applyControlSkin($control)
+ {
+ if(($theme=$this->getTheme())!==null)
+ $theme->applySkin($control);
+ }
+ public function applyControlStyleSheet($control)
+ {
+ if(($theme=$this->getStyleSheetTheme())!==null)
+ $theme->applySkin($control);
+ }
+ public function getClientScript()
+ {
+ if(!$this->_clientScript) {
+ $className = $classPath = $this->getService()->getClientScriptManagerClass();
+ Prado::using($className);
+ if(($pos=strrpos($className,'.'))!==false)
+ $className=substr($className,$pos+1);
+ if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
+ throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
+ $this->_clientScript=new $className($this);
+ }
+ return $this->_clientScript;
+ }
+ public function onPreInit($param)
+ {
+ $this->raiseEvent('OnPreInit',$this,$param);
+ }
+ public function onInitComplete($param)
+ {
+ $this->raiseEvent('OnInitComplete',$this,$param);
+ }
+ public function onPreLoad($param)
+ {
+ $this->raiseEvent('OnPreLoad',$this,$param);
+ }
+ public function onLoadComplete($param)
+ {
+ $this->raiseEvent('OnLoadComplete',$this,$param);
+ }
+ public function onPreRenderComplete($param)
+ {
+ $this->raiseEvent('OnPreRenderComplete',$this,$param);
+ $cs=$this->getClientScript();
+ $theme=$this->getTheme();
+ if($theme instanceof ITheme)
+ {
+ foreach($theme->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($theme->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+ $styleSheet=$this->getStyleSheetTheme();
+ if($styleSheet instanceof ITheme)
+ {
+ foreach($styleSheet->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($styleSheet->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+ if($cs->getRequiresHead() && $this->getHead()===null)
+ throw new TConfigurationException('page_head_required');
+ }
+ private function getCssMediaType($url)
+ {
+ $segs=explode('.',basename($url));
+ if(isset($segs[2]))
+ return $segs[count($segs)-2];
+ else
+ return '';
+ }
+ public function onSaveStateComplete($param)
+ {
+ $this->raiseEvent('OnSaveStateComplete',$this,$param);
+ }
+ private function determinePostBackMode()
+ {
+ $postData=$this->getRequest();
+ if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
+ $this->_postData=$postData;
+ }
+ public function getIsPostBack()
+ {
+ return $this->_postData!==null;
+ }
+ public function getIsCallback()
+ {
+ return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
+ }
+ public function saveState()
+ {
+ parent::saveState();
+ $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
+ }
+ public function loadState()
+ {
+ parent::loadState();
+ $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
+ }
+ protected function loadPageState()
+ {
+ $state=$this->getStatePersister()->load();
+ $this->loadStateRecursive($state,$this->getEnableViewState());
+ }
+ protected function savePageState()
+ {
+ $state=&$this->saveStateRecursive($this->getEnableViewState());
+ $this->getStatePersister()->save($state);
+ }
+ protected function isSystemPostField($field)
+ {
+ return isset(self::$_systemPostFields[$field]);
+ }
+ public function registerRequiresPostData($control)
+ {
+ $id=is_string($control)?$control:$control->getUniqueID();
+ $this->_controlsRegisteredForPostData[$id]=true;
+ $params=func_get_args();
+ foreach($this->getCachingStack() as $item)
+ $item->registerAction('Page','registerRequiresPostData',array($id));
+ }
+ public function getPostBackEventTarget()
+ {
+ if($this->_postBackEventTarget===null && $this->_postData!==null)
+ {
+ $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
+ if(!empty($eventTarget))
+ $this->_postBackEventTarget=$this->findControl($eventTarget);
+ }
+ return $this->_postBackEventTarget;
+ }
+ public function setPostBackEventTarget(TControl $control)
+ {
+ $this->_postBackEventTarget=$control;
+ }
+ public function getPostBackEventParameter()
+ {
+ if($this->_postBackEventParameter===null && $this->_postData!==null)
+ {
+ if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
+ $this->_postBackEventParameter='';
+ }
+ return $this->_postBackEventParameter;
+ }
+ public function setPostBackEventParameter($value)
+ {
+ $this->_postBackEventParameter=$value;
+ }
+ protected function processPostData($postData,$beforeLoad)
+ {
+ $this->_isLoadingPostData=true;
+ if($beforeLoad)
+ $this->_restPostData=new TMap;
+ foreach($postData as $key=>$value)
+ {
+ if($this->isSystemPostField($key))
+ continue;
+ else if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else if($control instanceof IPostBackEventHandler &&
+ empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
+ {
+ $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); }
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ else if($beforeLoad)
+ $this->_restPostData->add($key,$value);
+ }
+ foreach($this->_controlsRequiringPostData as $key=>$value)
+ {
+ if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$this->_postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else
+ throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ }
+ $this->_isLoadingPostData=false;
+ }
+ public function getIsLoadingPostData()
+ {
+ return $this->_isLoadingPostData;
+ }
+ protected function raiseChangedEvents()
+ {
+ foreach($this->_controlsPostDataChanged as $control)
+ $control->raisePostDataChangedEvent();
+ }
+ protected function raisePostBackEvent()
+ {
+ if(($postBackHandler=$this->getPostBackEventTarget())===null)
+ $this->validate();
+ else if($postBackHandler instanceof IPostBackEventHandler)
+ $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
+ }
+ public function getInFormRender()
+ {
+ return $this->_inFormRender;
+ }
+ public function ensureRenderInForm($control)
+ {
+ if(!$this->getIsCallback() && !$this->_inFormRender)
+ throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
+ }
+ public function beginFormRender($writer)
+ {
+ if($this->_formRendered)
+ throw new TConfigurationException('page_form_duplicated');
+ $this->_formRendered=true;
+ $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
+ $this->_inFormRender=true;
+ }
+ public function endFormRender($writer)
+ {
+ if($this->_focus)
+ {
+ if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
+ $focus=$this->_focus->getClientID();
+ else
+ $focus=$this->_focus;
+ $this->getClientScript()->registerFocusControl($focus);
+ }
+ else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
+ $this->getClientScript()->registerFocusControl($lastFocus);
+ $this->_inFormRender=false;
+ }
+ public function setFocus($value)
+ {
+ $this->_focus=$value;
+ }
+ public function getClientSupportsJavaScript()
+ {
+ return $this->_enableJavaScript;
+ }
+ public function setClientSupportsJavaScript($value)
+ {
+ $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
+ }
+ public function getHead()
+ {
+ return $this->_head;
+ }
+ public function setHead(THead $value)
+ {
+ if($this->_head)
+ throw new TInvalidOperationException('page_head_duplicated');
+ $this->_head=$value;
+ if($this->_title!==null)
+ {
+ $this->_head->setTitle($this->_title);
+ $this->_title=null;
+ }
+ }
+ public function getTitle()
+ {
+ if($this->_head)
+ return $this->_head->getTitle();
+ else
+ return $this->_title===null ? '' : $this->_title;
+ }
+ public function setTitle($value)
+ {
+ if($this->_head)
+ $this->_head->setTitle($value);
+ else
+ $this->_title=$value;
+ }
+ public function getClientState()
+ {
+ return $this->_clientState;
+ }
+ public function setClientState($state)
+ {
+ $this->_clientState=$state;
+ }
+ public function getRequestClientState()
+ {
+ return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
+ }
+ public function getStatePersisterClass()
+ {
+ return $this->_statePersisterClass;
+ }
+ public function setStatePersisterClass($value)
+ {
+ $this->_statePersisterClass=$value;
+ }
+ public function getStatePersister()
+ {
+ if($this->_statePersister===null)
+ {
+ $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
+ if(!($this->_statePersister instanceof IPageStatePersister))
+ throw new TInvalidDataTypeException('page_statepersister_invalid');
+ $this->_statePersister->setPage($this);
+ }
+ return $this->_statePersister;
+ }
+ public function getEnableStateValidation()
+ {
+ return $this->_enableStateValidation;
+ }
+ public function setEnableStateValidation($value)
+ {
+ $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
+ }
+ public function getEnableStateEncryption()
+ {
+ return $this->_enableStateEncryption;
+ }
+ public function setEnableStateEncryption($value)
+ {
+ $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
+ }
+ public function getEnableStateCompression()
+ {
+ return $this->_enableStateCompression;
+ }
+ public function setEnableStateCompression($value)
+ {
+ $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
+ }
+ public function getPagePath()
+ {
+ return $this->_pagePath;
+ }
+ public function setPagePath($value)
+ {
+ $this->_pagePath=$value;
+ }
+ public function registerCachingAction($context,$funcName,$funcParams)
+ {
+ if($this->_cachingStack)
+ {
+ foreach($this->_cachingStack as $cache)
+ $cache->registerAction($context,$funcName,$funcParams);
+ }
+ }
+ public function getCachingStack()
+ {
+ if(!$this->_cachingStack)
+ $this->_cachingStack=new TStack;
+ return $this->_cachingStack;
+ }
+ public function flushWriter()
+ {
+ if ($this->_writer)
+ $this->Response->write($this->_writer->flush());
+ }
+}
+interface IPageStatePersister
+{
+ public function getPage();
+ public function setPage(TPage $page);
+ public function save($state);
+ public function load();
+}
+class TPageStateFormatter
+{
+ public static function serialize($page,$data)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateValidation())
+ $str=$sm->hashData(serialize($data));
+ else
+ $str=serialize($data);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=gzcompress($str);
+ if($page->getEnableStateEncryption())
+ $str=$sm->encrypt($str);
+ return base64_encode($str);
+ }
+ public static function unserialize($page,$data)
+ {
+ $str=base64_decode($data);
+ if($str==='')
+ return null;
+ if($str!==false)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateEncryption())
+ $str=$sm->decrypt($str);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=@gzuncompress($str);
+ if($page->getEnableStateValidation())
+ {
+ if(($str=$sm->validateData($str))!==false)
+ return unserialize($str);
+ }
+ else
+ return unserialize($str);
+ }
+ return null;
+ }
+}
+class TOutputCache extends TControl implements INamingContainer
+{
+ const CACHE_ID_PREFIX='prado:outputcache';
+ private $_cacheModuleID='';
+ private $_dataCached=false;
+ private $_cacheAvailable=false;
+ private $_cacheChecked=false;
+ private $_cacheKey=null;
+ private $_duration=60;
+ private $_cache=null;
+ private $_contents;
+ private $_state;
+ private $_actions=array();
+ private $_varyByParam='';
+ private $_keyPrefix='';
+ private $_varyBySession=false;
+ private $_cachePostBack=false;
+ private $_cacheTime=0;
+ public function getAllowChildControls()
+ {
+ $this->determineCacheability();
+ return !$this->_dataCached;
+ }
+ private function determineCacheability()
+ {
+ if(!$this->_cacheChecked)
+ {
+ $this->_cacheChecked=true;
+ if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
+ {
+ if($this->_cacheModuleID!=='')
+ {
+ $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
+ if(!($this->_cache instanceof ICache))
+ throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
+ }
+ else
+ $this->_cache=$this->getApplication()->getCache();
+ if($this->_cache!==null)
+ {
+ $this->_cacheAvailable=true;
+ $data=$this->_cache->get($this->getCacheKey());
+ if(is_array($data))
+ {
+ $param=new TOutputCacheCheckDependencyEventParameter;
+ $param->setCacheTime(isset($data[3])?$data[3]:0);
+ $this->onCheckDependency($param);
+ $this->_dataCached=$param->getIsValid();
+ }
+ else
+ $this->_dataCached=false;
+ if($this->_dataCached)
+ list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
+ }
+ }
+ }
+ }
+ protected function initRecursive($namingContainer=null)
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::initRecursive($namingContainer);
+ $stack->pop();
+ }
+ else
+ parent::initRecursive($namingContainer);
+ }
+ protected function loadRecursive()
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::loadRecursive();
+ $stack->pop();
+ }
+ else
+ {
+ if($this->_dataCached)
+ $this->performActions();
+ parent::loadRecursive();
+ }
+ }
+ private function performActions()
+ {
+ $page=$this->getPage();
+ $cs=$page->getClientScript();
+ foreach($this->_actions as $action)
+ {
+ if($action[0]==='Page.ClientScript')
+ call_user_func_array(array($cs,$action[1]),$action[2]);
+ else if($action[0]==='Page')
+ call_user_func_array(array($page,$action[1]),$action[2]);
+ else
+ call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
+ }
+ }
+ protected function preRenderRecursive()
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::preRenderRecursive();
+ $stack->pop();
+ }
+ else
+ parent::preRenderRecursive();
+ }
+ protected function loadStateRecursive(&$state,$needViewState=true)
+ {
+ $st=unserialize($state);
+ parent::loadStateRecursive($st,$needViewState);
+ }
+ protected function &saveStateRecursive($needViewState=true)
+ {
+ if($this->_dataCached)
+ return $this->_state;
+ else
+ {
+ $st=parent::saveStateRecursive($needViewState);
+ $this->_state=serialize($st);
+ return $this->_state;
+ }
+ }
+ public function registerAction($context,$funcName,$funcParams)
+ {
+ $this->_actions[]=array($context,$funcName,$funcParams);
+ }
+ public function getCacheKey()
+ {
+ if($this->_cacheKey===null)
+ $this->_cacheKey=$this->calculateCacheKey();
+ return $this->_cacheKey;
+ }
+ protected function calculateCacheKey()
+ {
+ $key=$this->getBaseCacheKey();
+ if($this->_varyBySession)
+ $key.=$this->getSession()->getSessionID();
+ if($this->_varyByParam!=='')
+ {
+ $params=array();
+ $request=$this->getRequest();
+ foreach(explode(',',$this->_varyByParam) as $name)
+ {
+ $name=trim($name);
+ $params[$name]=$request->itemAt($name);
+ }
+ $key.=serialize($params);
+ }
+ $param=new TOutputCacheCalculateKeyEventParameter;
+ $this->onCalculateKey($param);
+ $key.=$param->getCacheKey();
+ return $key;
+ }
+ protected function getBaseCacheKey()
+ {
+ return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
+ }
+ public function getCacheModuleID()
+ {
+ return $this->_cacheModuleID;
+ }
+ public function setCacheModuleID($value)
+ {
+ $this->_cacheModuleID=$value;
+ }
+ public function setCacheKeyPrefix($value)
+ {
+ $this->_keyPrefix=$value;
+ }
+ public function getCacheTime()
+ {
+ return $this->_cacheTime;
+ }
+ protected function getCacheDependency()
+ {
+ return null;
+ }
+ public function getContentCached()
+ {
+ return $this->_dataCached;
+ }
+ public function getDuration()
+ {
+ return $this->_duration;
+ }
+ public function setDuration($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
+ $this->_duration=$value;
+ }
+ public function getVaryByParam()
+ {
+ return $this->_varyByParam;
+ }
+ public function setVaryByParam($value)
+ {
+ $this->_varyByParam=trim($value);
+ }
+ public function getVaryBySession()
+ {
+ return $this->_varyBySession;
+ }
+ public function setVaryBySession($value)
+ {
+ $this->_varyBySession=TPropertyValue::ensureBoolean($value);
+ }
+ public function getCachingPostBack()
+ {
+ return $this->_cachePostBack;
+ }
+ public function setCachingPostBack($value)
+ {
+ $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
+ }
+ public function onCheckDependency($param)
+ {
+ $this->raiseEvent('OnCheckDependency',$this,$param);
+ }
+ public function onCalculateKey($param)
+ {
+ $this->raiseEvent('OnCalculateKey',$this,$param);
+ }
+ public function render($writer)
+ {
+ if($this->_dataCached)
+ $writer->write($this->_contents);
+ else if($this->_cacheAvailable)
+ {
+ $textwriter = new TTextWriter();
+ $multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
+ $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::render($htmlWriter);
+ $stack->pop();
+ $content=$textwriter->flush();
+ $data=array($content,$this->_state,$this->_actions,time());
+ $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
+ }
+ else
+ parent::render($writer);
+ }
+}
+class TOutputCacheCheckDependencyEventParameter extends TEventParameter
+{
+ private $_isValid=true;
+ private $_cacheTime=0;
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+ public function getCacheTime()
+ {
+ return $this->_cacheTime;
+ }
+ public function setCacheTime($value)
+ {
+ $this->_cacheTime=TPropertyValue::ensureInteger($value);
+ }
+}
+class TOutputCacheCalculateKeyEventParameter extends TEventParameter
+{
+ private $_cacheKey='';
+ public function getCacheKey()
+ {
+ return $this->_cacheKey;
+ }
+ public function setCacheKey($value)
+ {
+ $this->_cacheKey=TPropertyValue::ensureString($value);
+ }
+}
+class TOutputCacheTextWriterMulti extends TTextWriter
+{
+ protected $_writers;
+ public function __construct(Array $writers)
+ {
+ $this->_writers = $writers;
+ }
+ public function write($s)
+ {
+ foreach($this->_writers as $writer)
+ $writer->write($s);
+ }
+ public function flush()
+ {
+ foreach($this->_writers as $writer)
+ $s = $writer->flush();
+ return $s;
+ }
+}
+class TTemplateManager extends TModule
+{
+ const TEMPLATE_FILE_EXT='.tpl';
+ const TEMPLATE_CACHE_PREFIX='prado:template:';
+ public function init($config)
+ {
+ $this->getService()->setTemplateManager($this);
+ }
+ public function getTemplateByClassName($className)
+ {
+ $class=new ReflectionClass($className);
+ $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
+ return $this->getTemplateByFileName($tplFile);
+ }
+ public function getTemplateByFileName($fileName)
+ {
+ if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
+ {
+ if(($cache=$this->getApplication()->getCache())===null)
+ return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
+ else
+ {
+ $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
+ if(is_array($array))
+ {
+ list($template,$timestamps)=$array;
+ if($this->getApplication()->getMode()===TApplicationMode::Performance)
+ return $template;
+ $cacheValid=true;
+ foreach($timestamps as $tplFile=>$timestamp)
+ {
+ if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
+ {
+ $cacheValid=false;
+ break;
+ }
+ }
+ if($cacheValid)
+ return $template;
+ }
+ $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
+ $includedFiles=$template->getIncludedFiles();
+ $timestamps=array();
+ $timestamps[$fileName]=filemtime($fileName);
+ foreach($includedFiles as $includedFile)
+ $timestamps[$includedFile]=filemtime($includedFile);
+ $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
+ return $template;
+ }
+ }
+ else
+ return null;
+ }
+ protected function getLocalizedTemplate($filename)
+ {
+ if(($app=$this->getApplication()->getGlobalization(false))===null)
+ return is_file($filename)?$filename:null;
+ foreach($app->getLocalizedResource($filename) as $file)
+ {
+ if(($file=realpath($file))!==false && is_file($file))
+ return $file;
+ }
+ return null;
+ }
+}
+class TTemplate extends TApplicationComponent implements ITemplate
+{
+ 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';
+ const CONFIG_DATABIND=0;
+ const CONFIG_EXPRESSION=1;
+ const CONFIG_ASSET=2;
+ const CONFIG_PARAMETER=3;
+ const CONFIG_LOCALIZATION=4;
+ const CONFIG_TEMPLATE=5;
+ private $_tpl=array();
+ private $_directive=array();
+ private $_contextPath;
+ private $_tplFile=null;
+ private $_startingLine=0;
+ private $_content;
+ private $_sourceTemplate=true;
+ private $_hashCode='';
+ private $_tplControl=null;
+ private $_includedFiles=array();
+ private $_includeAtLine=array();
+ private $_includeLines=array();
+ public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
+ {
+ $this->_sourceTemplate=$sourceTemplate;
+ $this->_contextPath=$contextPath;
+ $this->_tplFile=$tplFile;
+ $this->_startingLine=$startingLine;
+ $this->_content=$template;
+ $this->_hashCode=md5($template);
+ $this->parse($template);
+ $this->_content=null; }
+ public function getTemplateFile()
+ {
+ return $this->_tplFile;
+ }
+ public function getIsSourceTemplate()
+ {
+ return $this->_sourceTemplate;
+ }
+ public function getContextPath()
+ {
+ return $this->_contextPath;
+ }
+ public function getDirective()
+ {
+ return $this->_directive;
+ }
+ public function getHashCode()
+ {
+ return $this->_hashCode;
+ }
+ public function &getItems()
+ {
+ return $this->_tpl;
+ }
+ public function instantiateIn($tplControl,$parentControl=null)
+ {
+ $this->_tplControl=$tplControl;
+ if($parentControl===null)
+ $parentControl=$tplControl;
+ if(($page=$tplControl->getPage())===null)
+ $page=$this->getService()->getRequestedPage();
+ $controls=array();
+ $directChildren=array();
+ foreach($this->_tpl as $key=>$object)
+ {
+ if($object[0]===-1)
+ $parent=$parentControl;
+ else if(isset($controls[$object[0]]))
+ $parent=$controls[$object[0]];
+ else
+ continue;
+ if(isset($object[2])) {
+ $component=Prado::createComponent($object[1]);
+ $properties=&$object[2];
+ if($component instanceof TControl)
+ {
+ if($component instanceof TOutputCache)
+ $component->setCacheKeyPrefix($this->_hashCode.$key);
+ $component->setTemplateControl($tplControl);
+ if(isset($properties['id']))
+ {
+ if(is_array($properties['id']))
+ $properties['id']=$component->evaluateExpression($properties['id'][1]);
+ $tplControl->registerObject($properties['id'],$component);
+ }
+ if(isset($properties['skinid']))
+ {
+ if(is_array($properties['skinid']))
+ $component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
+ else
+ $component->setSkinID($properties['skinid']);
+ unset($properties['skinid']);
+ }
+ $component->trackViewState(false);
+ $component->applyStyleSheetSkin($page);
+ foreach($properties as $name=>$value)
+ $this->configureControl($component,$name,$value);
+ $component->trackViewState(true);
+ if($parent===$parentControl)
+ $directChildren[]=$component;
+ else
+ $component->createdOnTemplate($parent);
+ if($component->getAllowChildControls())
+ $controls[$key]=$component;
+ }
+ else if($component instanceof TComponent)
+ {
+ $controls[$key]=$component;
+ if(isset($properties['id']))
+ {
+ if(is_array($properties['id']))
+ $properties['id']=$component->evaluateExpression($properties['id'][1]);
+ $tplControl->registerObject($properties['id'],$component);
+ if(!$component->hasProperty('id'))
+ unset($properties['id']);
+ }
+ foreach($properties as $name=>$value)
+ $this->configureComponent($component,$name,$value);
+ if($parent===$parentControl)
+ $directChildren[]=$component;
+ else
+ $component->createdOnTemplate($parent);
+ }
+ }
+ else
+ {
+ if($object[1] instanceof TCompositeLiteral)
+ {
+ $o=clone $object[1];
+ $o->setContainer($tplControl);
+ if($parent===$parentControl)
+ $directChildren[]=$o;
+ else
+ $parent->addParsedObject($o);
+ }
+ else
+ {
+ if($parent===$parentControl)
+ $directChildren[]=$object[1];
+ else
+ $parent->addParsedObject($object[1]);
+ }
+ }
+ }
+ foreach($directChildren as $control)
+ {
+ if($control instanceof TComponent)
+ $control->createdOnTemplate($parentControl);
+ else
+ $parentControl->addParsedObject($control);
+ }
+ }
+ protected function configureControl($control,$name,$value)
+ {
+ if(strncasecmp($name,'on',2)===0) $this->configureEvent($control,$name,$value,$control);
+ else if(($pos=strrpos($name,'.'))===false) $this->configureProperty($control,$name,$value);
+ else $this->configureSubProperty($control,$name,$value);
+ }
+ protected function configureComponent($component,$name,$value)
+ {
+ if(strpos($name,'.')===false) $this->configureProperty($component,$name,$value);
+ else $this->configureSubProperty($component,$name,$value);
+ }
+ protected function configureEvent($control,$name,$value,$contextControl)
+ {
+ if(strpos($value,'.')===false)
+ $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
+ else
+ $control->attachEventHandler($name,array($contextControl,$value));
+ }
+ protected function configureProperty($component,$name,$value)
+ {
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case self::CONFIG_DATABIND:
+ $component->bindProperty($name,$value[1]);
+ break;
+ case self::CONFIG_EXPRESSION:
+ if($component instanceof TControl)
+ $component->autoBindProperty($name,$value[1]);
+ else
+ {
+ $setter='set'.$name;
+ $component->$setter($this->_tplControl->evaluateExpression($value[1]));
+ }
+ break;
+ case self::CONFIG_TEMPLATE:
+ $setter='set'.$name;
+ $component->$setter($value[1]);
+ break;
+ case self::CONFIG_ASSET: $setter='set'.$name;
+ $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
+ $component->$setter($url);
+ break;
+ case self::CONFIG_PARAMETER: $setter='set'.$name;
+ $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case self::CONFIG_LOCALIZATION:
+ $setter='set'.$name;
+ $component->$setter(Prado::localize($value[1]));
+ break;
+ default: throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
+ break;
+ }
+ }
+ else
+ {
+ if (substr($name,0,2)=='js')
+ if ($value and !($value instanceof TJavaScriptLiteral))
+ $value = new TJavaScriptLiteral($value);
+ $setter='set'.$name;
+ $component->$setter($value);
+ }
+ }
+ protected function configureSubProperty($component,$name,$value)
+ {
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case self::CONFIG_DATABIND: $component->bindProperty($name,$value[1]);
+ break;
+ case self::CONFIG_EXPRESSION: if($component instanceof TControl)
+ $component->autoBindProperty($name,$value[1]);
+ else
+ $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
+ break;
+ case self::CONFIG_TEMPLATE:
+ $component->setSubProperty($name,$value[1]);
+ break;
+ case self::CONFIG_ASSET: $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
+ $component->setSubProperty($name,$url);
+ break;
+ case self::CONFIG_PARAMETER: $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case self::CONFIG_LOCALIZATION:
+ $component->setSubProperty($name,Prado::localize($value[1]));
+ break;
+ default: throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
+ break;
+ }
+ }
+ else
+ $component->setSubProperty($name,$value);
+ }
+ protected function parse($input)
+ {
+ $input=$this->preprocess($input);
+ $tpl=&$this->_tpl;
+ $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
+ $expectPropEnd=false;
+ $textStart=0;
+ $stack=array();
+ $container=-1;
+ $matchEnd=0;
+ $c=0;
+ $this->_directive=null;
+ try
+ {
+ for($i=0;$i<$n;++$i)
+ {
+ $match=&$matches[$i];
+ $str=$match[0][0];
+ $matchStart=$match[0][1];
+ $matchEnd=$matchStart+strlen($str)-1;
+ if(strpos($str,'<com:')===0) {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $type=$match[1][0];
+ $attributes=$this->parseAttributes($match[2][0],$match[2][1]);
+ $this->validateAttributes($type,$attributes);
+ $tpl[$c++]=array($container,$type,$attributes);
+ if($str[strlen($str)-2]!=='/') {
+ $stack[] = $type;
+ $container=$c-1;
+ }
+ }
+ else if(strpos($str,'</com:')===0) {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $type=$match[1][0];
+ if(empty($stack))
+ throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
+ $name=array_pop($stack);
+ if($name!==$type)
+ {
+ $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ $container=$tpl[$container][0];
+ }
+ else if(strpos($str,'<%@')===0) {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ if(isset($tpl[0]) || $this->_directive!==null)
+ throw new TConfigurationException('template_directive_nonunique');
+ $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
+ }
+ else if(strpos($str,'<%')===0) {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $literal=trim($match[5][0]);
+ if($str[2]==='=') $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
+ else if($str[2]==='%') $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
+ else if($str[2]==='#')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
+ else if($str[2]==='$')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
+ else if($str[2]==='~')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
+ else if($str[2]==='/')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'"));
+ else if($str[2]==='[')
+ {
+ $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
+ }
+ }
+ else if(strpos($str,'<prop:')===0) {
+ if(strrpos($str,'/>')===strlen($str)-2) {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $prop=strtolower($match[6][0]);
+ $attrs=$this->parseAttributes($match[7][0],$match[7][1]);
+ $attributes=array();
+ foreach($attrs as $name=>$value)
+ $attributes[$prop.'.'.$name]=$value;
+ $type=$tpl[$container][1];
+ $this->validateAttributes($type,$attributes);
+ foreach($attributes as $name=>$value)
+ {
+ if(isset($tpl[$container][2][$name]))
+ throw new TConfigurationException('template_property_duplicated',$name);
+ $tpl[$container][2][$name]=$value;
+ }
+ }
+ else {
+ $prop=strtolower($match[3][0]);
+ $stack[] = '@'.$prop;
+ if(!$expectPropEnd)
+ {
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $expectPropEnd=true;
+ }
+ }
+ }
+ else if(strpos($str,'</prop:')===0) {
+ $prop=strtolower($match[3][0]);
+ if(empty($stack))
+ throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
+ $name=array_pop($stack);
+ if($name!=='@'.$prop)
+ {
+ $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
+ {
+ if($matchStart>$textStart)
+ {
+ $value=substr($input,$textStart,$matchStart-$textStart);
+ if(substr($prop,-8,8)==='template')
+ $value=$this->parseTemplateProperty($value,$textStart);
+ else
+ $value=$this->parseAttribute($value);
+ if($container>=0)
+ {
+ $type=$tpl[$container][1];
+ $this->validateAttributes($type,array($prop=>$value));
+ if(isset($tpl[$container][2][$prop]))
+ throw new TConfigurationException('template_property_duplicated',$prop);
+ $tpl[$container][2][$prop]=$value;
+ }
+ else $this->_directive[$prop]=$value;
+ $textStart=$matchEnd+1;
+ }
+ $expectPropEnd=false;
+ }
+ }
+ else if(strpos($str,'<!--')===0) {
+ if($expectPropEnd)
+ throw new TConfigurationException('template_comments_forbidden');
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ }
+ else
+ throw new TConfigurationException('template_matching_unexpected',$match);
+ }
+ if(!empty($stack))
+ {
+ $name=array_pop($stack);
+ $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ if($textStart<strlen($input))
+ $tpl[$c++]=array($container,substr($input,$textStart));
+ }
+ catch(Exception $e)
+ {
+ if(($e instanceof TException) && ($e instanceof TTemplateException))
+ throw $e;
+ if($matchEnd===0)
+ $line=$this->_startingLine+1;
+ else
+ $line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
+ $this->handleException($e,$line,$input);
+ }
+ if($this->_directive===null)
+ $this->_directive=array();
+ $objects=array();
+ $parent=null;
+ $merged=array();
+ foreach($tpl as $id=>$object)
+ {
+ if(isset($object[2]) || $object[0]!==$parent)
+ {
+ if($parent!==null)
+ {
+ if(count($merged[1])===1 && is_string($merged[1][0]))
+ $objects[$id-1]=array($merged[0],$merged[1][0]);
+ else
+ $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
+ }
+ if(isset($object[2]))
+ {
+ $parent=null;
+ $objects[$id]=$object;
+ }
+ else
+ {
+ $parent=$object[0];
+ $merged=array($parent,array($object[1]));
+ }
+ }
+ else
+ $merged[1][]=$object[1];
+ }
+ if($parent!==null)
+ {
+ if(count($merged[1])===1 && is_string($merged[1][0]))
+ $objects[$id]=array($merged[0],$merged[1][0]);
+ else
+ $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
+ }
+ $tpl=$objects;
+ return $objects;
+ }
+ protected function parseAttributes($str,$offset)
+ {
+ if($str==='')
+ return array();
+ $pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
+ $attributes=array();
+ $n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
+ for($i=0;$i<$n;++$i)
+ {
+ $match=&$matches[$i];
+ $name=strtolower($match[1][0]);
+ if(isset($attributes[$name]))
+ throw new TConfigurationException('template_property_duplicated',$name);
+ $value=$match[2][0];
+ if(substr($name,-8,8)==='template')
+ {
+ if($value[0]==='\'' || $value[0]==='"')
+ $attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
+ else
+ $attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
+ }
+ else
+ {
+ if($value[0]==='\'' || $value[0]==='"')
+ $attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
+ else
+ $attributes[$name]=$this->parseAttribute($value);
+ }
+ }
+ return $attributes;
+ }
+ protected function parseTemplateProperty($content,$offset)
+ {
+ $line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
+ return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
+ }
+ protected function parseAttribute($value)
+ {
+ if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
+ {
+ $isDataBind=false;
+ $textStart=0;
+ $expr='';
+ for($i=0;$i<$n;++$i)
+ {
+ $match=$matches[0][$i];
+ $token=$match[0];
+ $offset=$match[1];
+ $length=strlen($token);
+ if($token[2]==='#')
+ $isDataBind=true;
+ if($offset>$textStart)
+ $expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
+ $expr.='.('.substr($token,3,$length-5).')';
+ $textStart=$offset+$length;
+ }
+ $length=strlen($value);
+ if($length>$textStart)
+ $expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
+ if($isDataBind)
+ return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
+ else
+ return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
+ }
+ else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
+ {
+ $value=$matches[1];
+ if($value[2]==='~')
+ return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
+ elseif($value[2]==='[')
+ return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
+ elseif($value[2]==='$')
+ return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
+ elseif($value[2]==='/') {
+ $literal = trim(substr($value,3,strlen($value)-5));
+ return array(self::CONFIG_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'");
+ }
+ }
+ else
+ return $value;
+ }
+ protected function validateAttributes($type,$attributes)
+ {
+ Prado::using($type);
+ if(($pos=strrpos($type,'.'))!==false)
+ $className=substr($type,$pos+1);
+ else
+ $className=$type;
+ $class=new ReflectionClass($className);
+ if(is_subclass_of($className,'TControl') || $className==='TControl')
+ {
+ foreach($attributes as $name=>$att)
+ {
+ if(($pos=strpos($name,'.'))!==false)
+ {
+ $subname=substr($name,0,$pos);
+ if(!$class->hasMethod('get'.$subname))
+ throw new TConfigurationException('template_property_unknown',$type,$subname);
+ }
+ else if(strncasecmp($name,'on',2)===0)
+ {
+ if(!$class->hasMethod($name))
+ throw new TConfigurationException('template_event_unknown',$type,$name);
+ else if(!is_string($att))
+ throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
+ }
+ else
+ {
+ if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)) )
+ {
+ if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
+ throw new TConfigurationException('template_property_readonly',$type,$name);
+ else
+ throw new TConfigurationException('template_property_unknown',$type,$name);
+ }
+ else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
+ {
+ if(strcasecmp($name,'id')===0)
+ throw new TConfigurationException('template_controlid_invalid',$type);
+ else if(strcasecmp($name,'skinid')===0)
+ throw new TConfigurationException('template_controlskinid_invalid',$type);
+ }
+ }
+ }
+ }
+ else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
+ {
+ foreach($attributes as $name=>$att)
+ {
+ if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
+ throw new TConfigurationException('template_databind_forbidden',$type,$name);
+ if(($pos=strpos($name,'.'))!==false)
+ {
+ $subname=substr($name,0,$pos);
+ if(!$class->hasMethod('get'.$subname))
+ throw new TConfigurationException('template_property_unknown',$type,$subname);
+ }
+ else if(strncasecmp($name,'on',2)===0)
+ throw new TConfigurationException('template_event_forbidden',$type,$name);
+ else
+ {
+ if(strcasecmp($name,'id')!==0 && !($class->hasMethod('set'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)))
+ {
+ if($class->hasMethod('get'.$name))
+ throw new TConfigurationException('template_property_readonly',$type,$name);
+ else
+ throw new TConfigurationException('template_property_unknown',$type,$name);
+ }
+ }
+ }
+ }
+ else
+ throw new TConfigurationException('template_component_required',$type);
+ }
+ public function getIncludedFiles()
+ {
+ return $this->_includedFiles;
+ }
+ protected function handleException($e,$line,$input=null)
+ {
+ $srcFile=$this->_tplFile;
+ if(($n=count($this->_includedFiles))>0) {
+ for($i=$n-1;$i>=0;--$i)
+ {
+ if($this->_includeAtLine[$i]<=$line)
+ {
+ if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
+ {
+ $line=$line-$this->_includeAtLine[$i]+1;
+ $srcFile=$this->_includedFiles[$i];
+ break;
+ }
+ else
+ $line=$line-$this->_includeLines[$i]+1;
+ }
+ }
+ }
+ $exception=new TTemplateException('template_format_invalid',$e->getMessage());
+ $exception->setLineNumber($line);
+ if(!empty($srcFile))
+ $exception->setTemplateFile($srcFile);
+ else
+ $exception->setTemplateSource($input);
+ throw $exception;
+ }
+ protected function preprocess($input)
+ {
+ if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
+ {
+ for($i=0;$i<$n;++$i)
+ {
+ $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
+ if($filePath!==null && is_file($filePath))
+ $this->_includedFiles[]=$filePath;
+ else
+ {
+ $errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
+ $this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
+ }
+ }
+ $base=0;
+ for($i=0;$i<$n;++$i)
+ {
+ $ext=file_get_contents($this->_includedFiles[$i]);
+ $length=strlen($matches[$i][0][0]);
+ $offset=$base+$matches[$i][0][1];
+ $this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
+ $this->_includeLines[$i]=count(explode("\n",$ext));
+ $input=substr_replace($input,$ext,$offset,$length);
+ $base+=strlen($ext)-$length;
+ }
+ }
+ return $input;
+ }
+ protected function isClassBehaviorMethod(ReflectionClass $class,$method)
+ {
+ $component=new ReflectionClass('TComponent');
+ $behaviors=$component->getStaticProperties();
+ if(!isset($behaviors['_um']))
+ return false;
+ foreach($behaviors['_um'] as $name=>$list)
+ {
+ if(strtolower($class->getShortName())!==$name && !$class->isSubclassOf($name)) continue;
+ foreach($list as $param)
+ {
+ if(method_exists($param->getBehavior(),$method))
+ return true;
+ }
+ }
+ return false;
+ }
+}
+class TThemeManager extends TModule
+{
+ const DEFAULT_BASEPATH='themes';
+ const DEFAULT_THEMECLASS = 'TTheme';
+ private $_themeClass=self::DEFAULT_THEMECLASS;
+ private $_initialized=false;
+ private $_basePath=null;
+ private $_baseUrl=null;
+ public function init($config)
+ {
+ $this->_initialized=true;
+ $service=$this->getService();
+ if($service instanceof TPageService)
+ $service->setThemeManager($this);
+ else
+ throw new TConfigurationException('thememanager_service_unavailable');
+ }
+ public function getTheme($name)
+ {
+ $themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
+ $themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
+ return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
+ }
+ public function setThemeClass($class) {
+ $this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
+ }
+ public function getThemeClass() {
+ return $this->_themeClass;
+ }
+ public function getAvailableThemes()
+ {
+ $themes=array();
+ $basePath=$this->getBasePath();
+ $folder=@opendir($basePath);
+ while($file=@readdir($folder))
+ {
+ if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
+ $themes[]=$file;
+ }
+ closedir($folder);
+ return $themes;
+ }
+ public function getBasePath()
+ {
+ if($this->_basePath===null)
+ {
+ $this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
+ if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
+ throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
+ $this->_basePath=$basePath;
+ }
+ return $this->_basePath;
+ }
+ public function setBasePath($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('thememanager_basepath_unchangeable');
+ else
+ {
+ $this->_basePath=Prado::getPathOfNamespace($value);
+ if($this->_basePath===null || !is_dir($this->_basePath))
+ throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
+ }
+ }
+ public function getBaseUrl()
+ {
+ if($this->_baseUrl===null)
+ {
+ $appPath=dirname($this->getRequest()->getApplicationFilePath());
+ $basePath=$this->getBasePath();
+ if(strpos($basePath,$appPath)===false)
+ throw new TConfigurationException('thememanager_baseurl_required');
+ $appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
+ $this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
+ }
+ return $this->_baseUrl;
+ }
+ public function setBaseUrl($value)
+ {
+ $this->_baseUrl=rtrim($value,'/');
+ }
+}
+class TTheme extends TApplicationComponent implements ITheme
+{
+ const THEME_CACHE_PREFIX='prado:theme:';
+ const SKIN_FILE_EXT='.skin';
+ private $_themePath;
+ private $_themeUrl;
+ private $_skins=null;
+ private $_name='';
+ private $_cssFiles=array();
+ private $_jsFiles=array();
+ public function __construct($themePath,$themeUrl)
+ {
+ $this->_themeUrl=$themeUrl;
+ $this->_themePath=realpath($themePath);
+ $this->_name=basename($themePath);
+ $cacheValid=false;
+ if(($cache=$this->getApplication()->getCache())!==null)
+ {
+ $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
+ if(is_array($array))
+ {
+ list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
+ if($this->getApplication()->getMode()!==TApplicationMode::Performance)
+ {
+ if(($dir=opendir($themePath))===false)
+ throw new TIOException('theme_path_inexistent',$themePath);
+ $cacheValid=true;
+ while(($file=readdir($dir))!==false)
+ {
+ if($file==='.' || $file==='..')
+ continue;
+ else if(basename($file,'.css')!==$file)
+ $this->_cssFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,'.js')!==$file)
+ $this->_jsFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
+ {
+ $cacheValid=false;
+ break;
+ }
+ }
+ closedir($dir);
+ if($cacheValid)
+ $this->_skins=$skins;
+ }
+ else
+ {
+ $cacheValid=true;
+ $this->_cssFiles=$cssFiles;
+ $this->_jsFiles=$jsFiles;
+ $this->_skins=$skins;
+ }
+ }
+ }
+ if(!$cacheValid)
+ {
+ $this->_cssFiles=array();
+ $this->_jsFiles=array();
+ $this->_skins=array();
+ if(($dir=opendir($themePath))===false)
+ throw new TIOException('theme_path_inexistent',$themePath);
+ while(($file=readdir($dir))!==false)
+ {
+ if($file==='.' || $file==='..')
+ continue;
+ else if(basename($file,'.css')!==$file)
+ $this->_cssFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,'.js')!==$file)
+ $this->_jsFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,self::SKIN_FILE_EXT)!==$file)
+ {
+ $template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
+ foreach($template->getItems() as $skin)
+ {
+ if(!isset($skin[2])) continue;
+ else if($skin[0]!==-1)
+ throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
+ $type=$skin[1];
+ $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
+ unset($skin[2]['skinid']);
+ if(isset($this->_skins[$type][$id]))
+ throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
+ $this->_skins[$type][$id]=$skin[2];
+ }
+ }
+ }
+ closedir($dir);
+ sort($this->_cssFiles);
+ sort($this->_jsFiles);
+ if($cache!==null)
+ $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
+ }
+ }
+ public function getName()
+ {
+ return $this->_name;
+ }
+ protected function setName($value)
+ {
+ $this->_name = $value;
+ }
+ public function getBaseUrl()
+ {
+ return $this->_themeUrl;
+ }
+ protected function setBaseUrl($value)
+ {
+ $this->_themeUrl=rtrim($value,'/');
+ }
+ public function getBasePath()
+ {
+ return $this->_themePath;
+ }
+ protected function setBasePath($value)
+ {
+ $this->_themePath=$value;
+ }
+ public function getSkins()
+ {
+ return $this->_skins;
+ }
+ protected function setSkins($value)
+ {
+ $this->_skins = $value;
+ }
+ public function applySkin($control)
+ {
+ $type=get_class($control);
+ if(($id=$control->getSkinID())==='')
+ $id=0;
+ if(isset($this->_skins[$type][$id]))
+ {
+ foreach($this->_skins[$type][$id] as $name=>$value)
+ {
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case TTemplate::CONFIG_EXPRESSION:
+ $value=$this->evaluateExpression($value[1]);
+ break;
+ case TTemplate::CONFIG_ASSET:
+ $value=$this->_themeUrl.'/'.ltrim($value[1],'/');
+ break;
+ case TTemplate::CONFIG_DATABIND:
+ $control->bindProperty($name,$value[1]);
+ break;
+ case TTemplate::CONFIG_PARAMETER:
+ $control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case TTemplate::CONFIG_TEMPLATE:
+ $control->setSubProperty($name,$value[1]);
+ break;
+ case TTemplate::CONFIG_LOCALIZATION:
+ $control->setSubProperty($name,Prado::localize($value[1]));
+ break;
+ default:
+ throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
+ break;
+ }
+ }
+ if(!is_array($value))
+ {
+ if(strpos($name,'.')===false) {
+ if($control->hasProperty($name))
+ {
+ if($control->canSetProperty($name))
+ {
+ $setter='set'.$name;
+ $control->$setter($value);
+ }
+ else
+ throw new TConfigurationException('theme_property_readonly',$type,$name);
+ }
+ else
+ throw new TConfigurationException('theme_property_undefined',$type,$name);
+ }
+ else $control->setSubProperty($name,$value);
+ }
+ }
+ return true;
+ }
+ else
+ return false;
+ }
+ public function getStyleSheetFiles()
+ {
+ return $this->_cssFiles;
+ }
+ protected function setStyleSheetFiles($value)
+ {
+ $this->_cssFiles=$value;
+ }
+ public function getJavaScriptFiles()
+ {
+ return $this->_jsFiles;
+ }
+ protected function setJavaScriptFiles($value)
+ {
+ $this->_jsFiles=$value;
+ }
+}
+class TPageService extends TService
+{
+ const CONFIG_FILE_XML='config.xml';
+ const CONFIG_FILE_PHP='config.php';
+ const DEFAULT_BASEPATH='Pages';
+ const FALLBACK_BASEPATH='pages';
+ const CONFIG_CACHE_PREFIX='prado:pageservice:';
+ const PAGE_FILE_EXT='.page';
+ private $_basePath=null;
+ private $_basePageClass='TPage';
+ private $_clientScriptManagerClass='System.Web.UI.TClientScriptManager';
+ private $_defaultPage='Home';
+ private $_pagePath=null;
+ private $_page=null;
+ private $_properties=array();
+ private $_initialized=false;
+ private $_themeManager=null;
+ private $_templateManager=null;
+ public function init($config)
+ {
+ $pageConfig=$this->loadPageConfig($config);
+ $this->initPageContext($pageConfig);
+ $this->_initialized=true;
+ }
+ protected function initPageContext($pageConfig)
+ {
+ $application=$this->getApplication();
+ foreach($pageConfig->getApplicationConfigurations() as $appConfig)
+ $application->applyConfiguration($appConfig);
+ $this->applyConfiguration($pageConfig);
+ }
+ protected function applyConfiguration($config)
+ {
+ $this->_properties=array_merge($this->_properties, $config->getProperties());
+ $this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
+ $pagePath=$this->getRequestedPagePath();
+ foreach($config->getExternalConfigurations() as $filePath=>$params)
+ {
+ list($configPagePath,$condition)=$params;
+ if($condition!==true)
+ $condition=$this->evaluateExpression($condition);
+ if($condition)
+ {
+ if(($path=Prado::getPathOfNamespace($filePath,Prado::getApplication()->getConfigurationFileExt()))===null || !is_file($path))
+ throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
+ $c=new TPageConfiguration($pagePath);
+ $c->loadFromFile($path,$configPagePath);
+ $this->applyConfiguration($c);
+ }
+ }
+ }
+ protected function determineRequestedPagePath()
+ {
+ $pagePath=$this->getRequest()->getServiceParameter();
+ if(empty($pagePath))
+ $pagePath=$this->getDefaultPage();
+ return $pagePath;
+ }
+ protected function loadPageConfig($config)
+ {
+ $application=$this->getApplication();
+ $pagePath=$this->getRequestedPagePath();
+ if(($cache=$application->getCache())===null)
+ {
+ $pageConfig=new TPageConfiguration($pagePath);
+ if($config!==null)
+ {
+ if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ $pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
+ else
+ $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
+ }
+ $pageConfig->loadFromFiles($this->getBasePath());
+ }
+ else
+ {
+ $configCached=true;
+ $currentTimestamp=array();
+ $arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
+ if(is_array($arr))
+ {
+ list($pageConfig,$timestamps)=$arr;
+ if($application->getMode()!==TApplicationMode::Performance)
+ {
+ foreach($timestamps as $fileName=>$timestamp)
+ {
+ if($fileName===0) {
+ $appConfigFile=$application->getConfigurationFile();
+ $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
+ if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
+ $configCached=false;
+ }
+ else
+ {
+ $currentTimestamp[$fileName]=@filemtime($fileName);
+ if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
+ $configCached=false;
+ }
+ }
+ }
+ }
+ else
+ {
+ $configCached=false;
+ $paths=explode('.',$pagePath);
+ $configPath=$this->getBasePath();
+ $fileName = $this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
+ ? self::CONFIG_FILE_PHP
+ : self::CONFIG_FILE_XML;
+ foreach($paths as $path)
+ {
+ $configFile=$configPath.DIRECTORY_SEPARATOR.$fileName;
+ $currentTimestamp[$configFile]=@filemtime($configFile);
+ $configPath.=DIRECTORY_SEPARATOR.$path;
+ }
+ $appConfigFile=$application->getConfigurationFile();
+ $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
+ }
+ if(!$configCached)
+ {
+ $pageConfig=new TPageConfiguration($pagePath);
+ if($config!==null)
+ {
+ if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ $pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
+ else
+ $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
+ }
+ $pageConfig->loadFromFiles($this->getBasePath());
+ $cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
+ }
+ }
+ return $pageConfig;
+ }
+ public function getTemplateManager()
+ {
+ if(!$this->_templateManager)
+ {
+ $this->_templateManager=new TTemplateManager;
+ $this->_templateManager->init(null);
+ }
+ return $this->_templateManager;
+ }
+ public function setTemplateManager(TTemplateManager $value)
+ {
+ $this->_templateManager=$value;
+ }
+ public function getThemeManager()
+ {
+ if(!$this->_themeManager)
+ {
+ $this->_themeManager=new TThemeManager;
+ $this->_themeManager->init(null);
+ }
+ return $this->_themeManager;
+ }
+ public function setThemeManager(TThemeManager $value)
+ {
+ $this->_themeManager=$value;
+ }
+ public function getRequestedPagePath()
+ {
+ if($this->_pagePath===null)
+ {
+ $this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
+ if(empty($this->_pagePath))
+ throw new THttpException(404,'pageservice_page_required');
+ }
+ return $this->_pagePath;
+ }
+ public function getRequestedPage()
+ {
+ return $this->_page;
+ }
+ public function getDefaultPage()
+ {
+ return $this->_defaultPage;
+ }
+ public function setDefaultPage($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
+ else
+ $this->_defaultPage=$value;
+ }
+ public function getDefaultPageUrl()
+ {
+ return $this->constructUrl($this->getDefaultPage());
+ }
+ public function getBasePath()
+ {
+ if($this->_basePath===null)
+ {
+ $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
+ if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
+ {
+ $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::FALLBACK_BASEPATH;
+ if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
+ throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
+ }
+ }
+ return $this->_basePath;
+ }
+ public function setBasePath($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('pageservice_basepath_unchangeable');
+ else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
+ throw new TConfigurationException('pageservice_basepath_invalid',$value);
+ $this->_basePath=realpath($path);
+ }
+ public function setBasePageClass($value)
+ {
+ $this->_basePageClass=$value;
+ }
+ public function getBasePageClass()
+ {
+ return $this->_basePageClass;
+ }
+ public function setClientScriptManagerClass($value)
+ {
+ $this->_clientScriptManagerClass=$value;
+ }
+ public function getClientScriptManagerClass()
+ {
+ return $this->_clientScriptManagerClass;
+ }
+ public function run()
+ {
+ $this->_page=$this->createPage($this->getRequestedPagePath());
+ $this->runPage($this->_page,$this->_properties);
+ }
+ protected function createPage($pagePath)
+ {
+ $path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
+ $hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
+ $hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
+ if(!$hasTemplateFile && !$hasClassFile)
+ throw new THttpException(404,'pageservice_page_unknown',$pagePath);
+ if($hasClassFile)
+ {
+ $className=basename($path);
+ if(!class_exists($className,false))
+ include_once($path.Prado::CLASS_FILE_EXT);
+ }
+ else
+ {
+ $className=$this->getBasePageClass();
+ Prado::using($className);
+ if(($pos=strrpos($className,'.'))!==false)
+ $className=substr($className,$pos+1);
+ }
+ if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
+ throw new THttpException(404,'pageservice_page_unknown',$pagePath);
+ $page=Prado::createComponent($className);
+ $page->setPagePath($pagePath);
+ if($hasTemplateFile)
+ $page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
+ return $page;
+ }
+ protected function runPage($page,$properties)
+ {
+ foreach($properties as $name=>$value)
+ $page->setSubProperty($name,$value);
+ $page->run($this->getResponse()->createHtmlWriter());
+ }
+ public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
+ {
+ return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
+ }
+}
+class TPageConfiguration extends TComponent
+{
+ private $_appConfigs=array();
+ private $_properties=array();
+ private $_rules=array();
+ private $_includes=array();
+ private $_pagePath='';
+ public function __construct($pagePath)
+ {
+ $this->_pagePath=$pagePath;
+ }
+ public function getExternalConfigurations()
+ {
+ return $this->_includes;
+ }
+ public function getProperties()
+ {
+ return $this->_properties;
+ }
+ public function getRules()
+ {
+ return $this->_rules;
+ }
+ public function getApplicationConfigurations()
+ {
+ return $this->_appConfigs;
+ }
+ public function loadFromFiles($basePath)
+ {
+ $paths=explode('.',$this->_pagePath);
+ $page=array_pop($paths);
+ $path=$basePath;
+ $configPagePath='';
+ $fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
+ ? TPageService::CONFIG_FILE_PHP
+ : TPageService::CONFIG_FILE_XML;
+ foreach($paths as $p)
+ {
+ $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
+ $path.=DIRECTORY_SEPARATOR.$p;
+ if($configPagePath==='')
+ $configPagePath=$p;
+ else
+ $configPagePath.='.'.$p;
+ }
+ $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
+ $this->_rules=new TAuthorizationRuleCollection($this->_rules);
+ }
+ public function loadFromFile($fname,$configPagePath)
+ {
+ if(empty($fname) || !is_file($fname))
+ return;
+ if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ $fcontent = include $fname;
+ $this->loadFromPhp($fcontent,dirname($fname),$configPagePath);
+ }
+ else
+ {
+ $dom=new TXmlDocument;
+ if($dom->loadFromFile($fname))
+ $this->loadFromXml($dom,dirname($fname),$configPagePath);
+ else
+ throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
+ }
+ }
+ public function loadFromPhp($config,$configPath,$configPagePath)
+ {
+ $this->loadApplicationConfigurationFromPhp($config,$configPath);
+ $this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath);
+ }
+ public function loadFromXml($dom,$configPath,$configPagePath)
+ {
+ $this->loadApplicationConfigurationFromXml($dom,$configPath);
+ $this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
+ }
+ public function loadApplicationConfigurationFromPhp($config,$configPath)
+ {
+ $appConfig=new TApplicationConfiguration;
+ $appConfig->loadFromPhp($config,$configPath);
+ $this->_appConfigs[]=$appConfig;
+ }
+ public function loadApplicationConfigurationFromXml($dom,$configPath)
+ {
+ $appConfig=new TApplicationConfiguration;
+ $appConfig->loadFromXml($dom,$configPath);
+ $this->_appConfigs[]=$appConfig;
+ }
+ public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath)
+ {
+ if(isset($config['authorization']) && is_array($config['authorization']))
+ {
+ $rules = array();
+ foreach($config['authorization'] as $authorization)
+ {
+ $patterns=isset($authorization['pages'])?$authorization['pages']:'';
+ $ruleApplies=false;
+ if(empty($patterns) || trim($patterns)==='*') $ruleApplies=true;
+ else
+ {
+ foreach(explode(',',$patterns) as $pattern)
+ {
+ if(($pattern=trim($pattern))!=='')
+ {
+ if($configPagePath!=='') $pattern=$configPagePath.'.'.$pattern;
+ if(strcasecmp($pattern,$this->_pagePath)===0)
+ {
+ $ruleApplies=true;
+ break;
+ }
+ if($pattern[strlen($pattern)-1]==='*') {
+ if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
+ {
+ $ruleApplies=true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if($ruleApplies)
+ {
+ $action = isset($authorization['action'])?$authorization['action']:'';
+ $users = isset($authorization['users'])?$authorization['users']:'';
+ $roles = isset($authorization['roles'])?$authorization['roles']:'';
+ $verb = isset($authorization['verb'])?$authorization['verb']:'';
+ $ips = isset($authorization['ips'])?$authorization['ips']:'';
+ $rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips);
+ }
+ }
+ $this->_rules=array_merge($rules,$this->_rules);
+ }
+ if(isset($config['pages']) && is_array($config['pages']))
+ {
+ if(isset($config['pages']['properties']))
+ {
+ $this->_properties = array_merge($this->_properties, $config['pages']['properties']);
+ unset($config['pages']['properties']);
+ }
+ foreach($config['pages'] as $id => $page)
+ {
+ $properties = array();
+ if(isset($page['properties']))
+ {
+ $properties=$page['properties'];
+ unset($page['properties']);
+ }
+ $matching=false;
+ $id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
+ if(strcasecmp($id,$this->_pagePath)===0)
+ $matching=true;
+ else if($id[strlen($id)-1]==='*') $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
+ if($matching)
+ $this->_properties=array_merge($this->_properties,$properties);
+ }
+ }
+ if(isset($config['includes']) && is_array($config['includes']))
+ {
+ foreach($config['includes'] as $include)
+ {
+ $when = isset($include['when'])?true:false;
+ if(!isset($include['file']))
+ throw new TConfigurationException('pageserviceconf_includefile_required');
+ $filePath = $include['file'];
+ if(isset($this->_includes[$filePath]))
+ $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
+ else
+ $this->_includes[$filePath]=array($configPagePath,$when);
+ }
+ }
+ }
+ public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
+ {
+ if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
+ {
+ $rules=array();
+ foreach($authorizationNode->getElements() as $node)
+ {
+ $patterns=$node->getAttribute('pages');
+ $ruleApplies=false;
+ if(empty($patterns) || trim($patterns)==='*') $ruleApplies=true;
+ else
+ {
+ foreach(explode(',',$patterns) as $pattern)
+ {
+ if(($pattern=trim($pattern))!=='')
+ {
+ if($configPagePath!=='') $pattern=$configPagePath.'.'.$pattern;
+ if(strcasecmp($pattern,$this->_pagePath)===0)
+ {
+ $ruleApplies=true;
+ break;
+ }
+ if($pattern[strlen($pattern)-1]==='*') {
+ if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
+ {
+ $ruleApplies=true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if($ruleApplies)
+ $rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
+ }
+ $this->_rules=array_merge($rules,$this->_rules);
+ }
+ if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
+ {
+ $this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
+ foreach($pagesNode->getElementsByTagName('page') as $node)
+ {
+ $properties=$node->getAttributes();
+ $id=$properties->remove('id');
+ if(empty($id))
+ throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
+ $matching=false;
+ $id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
+ if(strcasecmp($id,$this->_pagePath)===0)
+ $matching=true;
+ else if($id[strlen($id)-1]==='*') $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
+ if($matching)
+ $this->_properties=array_merge($this->_properties,$properties->toArray());
+ }
+ }
+ foreach($dom->getElementsByTagName('include') as $node)
+ {
+ if(($when=$node->getAttribute('when'))===null)
+ $when=true;
+ if(($filePath=$node->getAttribute('file'))===null)
+ throw new TConfigurationException('pageserviceconf_includefile_required');
+ if(isset($this->_includes[$filePath]))
+ $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
+ else
+ $this->_includes[$filePath]=array($configPagePath,$when);
+ }
+ }
+}
+class TAssetManager extends TModule
+{
+ const DEFAULT_BASEPATH='assets';
+ private $_basePath=null;
+ private $_baseUrl=null;
+ private $_checkTimestamp=false;
+ private $_application;
+ private $_published=array();
+ private $_initialized=false;
+ public function init($config)
+ {
+ $application=$this->getApplication();
+ if($this->_basePath===null)
+ $this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
+ if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
+ throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
+ if($this->_baseUrl===null)
+ $this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
+ $application->setAssetManager($this);
+ $this->_initialized=true;
+ }
+ public function getBasePath()
+ {
+ return $this->_basePath;
+ }
+ public function setBasePath($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
+ else
+ {
+ $this->_basePath=Prado::getPathOfNamespace($value);
+ if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
+ throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value);
+ }
+ }
+ public function getBaseUrl()
+ {
+ return $this->_baseUrl;
+ }
+ public function setBaseUrl($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
+ else
+ $this->_baseUrl=rtrim($value,'/');
+ }
+ public function publishFilePath($path,$checkTimestamp=false)
+ {
+ if(isset($this->_published[$path]))
+ return $this->_published[$path];
+ else if(empty($path) || ($fullpath=realpath($path))===false)
+ throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
+ else if(is_file($fullpath))
+ {
+ $dir=$this->hash(dirname($fullpath));
+ $fileName=basename($fullpath);
+ $dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
+ if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
+ $this->copyFile($fullpath,$dst);
+ return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
+ }
+ else
+ {
+ $dir=$this->hash($fullpath);
+ if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
+ {
+ $this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
+ }
+ return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
+ }
+ }
+ public function getPublished()
+ {
+ return $this->_published;
+ }
+ protected function setPublished($values=array())
+ {
+ $this->_published = $values;
+ }
+ public function getPublishedPath($path)
+ {
+ $path=realpath($path);
+ if(is_file($path))
+ return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
+ else
+ return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
+ }
+ public function getPublishedUrl($path)
+ {
+ $path=realpath($path);
+ if(is_file($path))
+ return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
+ else
+ return $this->_baseUrl.'/'.$this->hash($path);
+ }
+ protected function hash($dir)
+ {
+ return sprintf('%x',crc32($dir.Prado::getVersion()));
+ }
+ protected function copyFile($src,$dst)
+ {
+ if(!is_dir($dst))
+ {
+ @mkdir($dst);
+ @chmod($dst, PRADO_CHMOD);
+ }
+ $dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
+ if(@filemtime($dstFile)<@filemtime($src))
+ {
+ @copy($src,$dstFile);
+ }
+ }
+ public function copyDirectory($src,$dst)
+ {
+ if(!is_dir($dst))
+ {
+ @mkdir($dst);
+ @chmod($dst, PRADO_CHMOD);
+ }
+ if($folder=@opendir($src))
+ {
+ while($file=@readdir($folder))
+ {
+ if($file==='.' || $file==='..' || $file==='.svn')
+ continue;
+ else if(is_file($src.DIRECTORY_SEPARATOR.$file))
+ {
+ if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
+ {
+ @copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
+ @chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
+ }
+ }
+ else
+ $this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
+ }
+ closedir($folder);
+ } else {
+ throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
+ }
+ }
+ public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
+ {
+ if(isset($this->_published[$md5sum]))
+ return $this->_published[$md5sum];
+ else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
+ throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
+ else
+ {
+ $dir=$this->hash(dirname($fullpath));
+ $fileName=basename($fullpath);
+ $dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
+ if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
+ {
+ if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
+ {
+ $this->copyFile($fullpath,$dst);
+ $this->deployTarFile($tarfile,$dst);
+ }
+ }
+ return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
+ }
+ }
+ protected function deployTarFile($path,$destination)
+ {
+ if(($fullpath=realpath($path))===false || !is_file($fullpath))
+ throw new TIOException('assetmanager_tarfile_invalid',$path);
+ else
+ {
+ Prado::using('System.IO.TTarFileExtractor');
+ $tar = new TTarFileExtractor($fullpath);
+ return $tar->extract($destination);
+ }
+ }
+}
+class TGlobalization extends TModule
+{
+ private $_defaultCharset = 'UTF-8';
+ private $_defaultCulture = 'en';
+ private $_charset=null;
+ private $_culture=null;
+ private $_translation;
+ private $_translateDefaultCulture=true;
+ public function init($config)
+ {
+ if($this->_charset===null)
+ $this->_charset=$this->getDefaultCharset();
+ if($this->_culture===null)
+ $this->_culture=$this->getDefaultCulture();
+ if($config!==null)
+ {
+ if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ $translation = isset($config['translate'])?$config['translate']:null;
+ else
+ {
+ $t = $config->getElementByTagName('translation');
+ $translation = ($t)?$t->getAttributes():null;
+ }
+ if($translation)
+ $this->setTranslationConfiguration($translation);
+ }
+ $this->getApplication()->setGlobalization($this);
+ }
+ public function getTranslateDefaultCulture()
+ {
+ return $this->_translateDefaultCulture;
+ }
+ public function setTranslateDefaultCulture($value)
+ {
+ $this->_translateDefaultCulture = TPropertyValue::ensureBoolean($value);
+ }
+ public function getDefaultCulture()
+ {
+ return $this->_defaultCulture;
+ }
+ public function setDefaultCulture($culture)
+ {
+ $this->_defaultCulture = str_replace('-','_',$culture);
+ }
+ public function getDefaultCharset()
+ {
+ return $this->_defaultCharset;
+ }
+ public function setDefaultCharset($charset)
+ {
+ $this->_defaultCharset = $charset;
+ }
+ public function getCulture()
+ {
+ return $this->_culture;
+ }
+ public function setCulture($culture)
+ {
+ $this->_culture = str_replace('-','_',$culture);
+ }
+ public function getCharset()
+ {
+ return $this->_charset;
+ }
+ public function setCharset($charset)
+ {
+ $this->_charset = $charset;
+ }
+ public function getTranslationConfiguration()
+ {
+ return (!$this->_translateDefaultCulture && ($this->getDefaultCulture() == $this->getCulture()))
+ ? null
+ : $this->_translation;
+ }
+ protected function setTranslationConfiguration($config)
+ {
+ if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
+ {
+ if($config['source'])
+ {
+ $config['source'] = Prado::getPathOfNamespace($config['source']);
+ if(!is_dir($config['source']))
+ {
+ if(@mkdir($config['source'])===false)
+ throw new TConfigurationException('globalization_source_path_failed',
+ $config['source']);
+ chmod($config['source'], PRADO_CHMOD); }
+ }
+ else
+ {
+ throw new TConfigurationException("invalid source dir '{$config['source']}'");
+ }
+ }
+ if($config['cache'])
+ {
+ $config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
+ if(!is_dir($config['cache']))
+ {
+ if(@mkdir($config['cache'])===false)
+ throw new TConfigurationException('globalization_cache_path_failed',
+ $config['cache']);
+ chmod($config['cache'], PRADO_CHMOD); }
+ }
+ $this->_translation = $config;
+ }
+ public function getTranslationCatalogue()
+ {
+ return $this->_translation['catalogue'];
+ }
+ public function setTranslationCatalogue($value)
+ {
+ $this->_translation['catalogue'] = $value;
+ }
+ public function getCultureVariants($culture=null)
+ {
+ if($culture===null) $culture = $this->getCulture();
+ $variants = explode('_', $culture);
+ $result = array();
+ for(; count($variants) > 0; array_pop($variants))
+ $result[] = implode('_', $variants);
+ return $result;
+ }
+ public function getLocalizedResource($file,$culture=null)
+ {
+ $files = array();
+ $variants = $this->getCultureVariants($culture);
+ $path = pathinfo($file);
+ foreach($variants as $variant)
+ $files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename'];
+ $filename = substr($path['basename'],0,strrpos($path['basename'],'.'));
+ foreach($variants as $variant)
+ $files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension'];
+ $files[] = $file;
+ return $files;
+ }
+}
+class TApplication extends TComponent
+{
+ const STATE_OFF='Off';
+ const STATE_DEBUG='Debug';
+ const STATE_NORMAL='Normal';
+ const STATE_PERFORMANCE='Performance';
+ const PAGE_SERVICE_ID='page';
+ const CONFIG_FILE_XML='application.xml';
+ const CONFIG_FILE_EXT_XML='.xml';
+ const CONFIG_TYPE_XML = 'xml';
+ const CONFIG_FILE_PHP='application.php';
+ const CONFIG_FILE_EXT_PHP='.php';
+ const CONFIG_TYPE_PHP = 'php';
+ const RUNTIME_PATH='runtime';
+ const CONFIGCACHE_FILE='config.cache';
+ const GLOBAL_FILE='global.cache';
+ private static $_steps=array(
+ 'onBeginRequest',
+ 'onLoadState',
+ 'onLoadStateComplete',
+ 'onAuthentication',
+ 'onAuthenticationComplete',
+ 'onAuthorization',
+ 'onAuthorizationComplete',
+ 'onPreRunService',
+ 'runService',
+ 'onSaveState',
+ 'onSaveStateComplete',
+ 'onPreFlushOutput',
+ 'flushOutput'
+ );
+ private $_id;
+ private $_uniqueID;
+ private $_requestCompleted=false;
+ private $_step;
+ private $_services;
+ private $_service;
+ private $_modules=array();
+ private $_lazyModules=array();
+ private $_parameters;
+ private $_configFile;
+ private $_configFileExt;
+ private $_configType;
+ private $_basePath;
+ private $_runtimePath;
+ private $_stateChanged=false;
+ private $_globals=array();
+ private $_cacheFile;
+ private $_errorHandler;
+ private $_request;
+ private $_response;
+ private $_session;
+ private $_cache;
+ private $_statePersister;
+ private $_user;
+ private $_globalization;
+ private $_security;
+ private $_assetManager;
+ private $_authRules;
+ private $_mode=TApplicationMode::Debug;
+ private $_pageServiceID = self::PAGE_SERVICE_ID;
+ public function __construct($basePath='protected',$cacheConfig=true, $configType=self::CONFIG_TYPE_XML)
+ {
+ Prado::setApplication($this);
+ $this->setConfigurationType($configType);
+ $this->resolvePaths($basePath);
+ if($cacheConfig)
+ $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
+ $this->_uniqueID=md5($this->_runtimePath);
+ $this->_parameters=new TMap;
+ $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
+ Prado::setPathOfAlias('Application',$this->_basePath);
+ }
+ protected function resolvePaths($basePath)
+ {
+ if(empty($basePath) || ($basePath=realpath($basePath))===false)
+ throw new TConfigurationException('application_basepath_invalid',$basePath);
+ if(is_dir($basePath) && is_file($basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName()))
+ $configFile=$basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName();
+ else if(is_file($basePath))
+ {
+ $configFile=$basePath;
+ $basePath=dirname($configFile);
+ }
+ else
+ $configFile=null;
+ $runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
+ if(is_writable($runtimePath))
+ {
+ if($configFile!==null)
+ {
+ $runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
+ if(!is_dir($runtimePath))
+ {
+ if(@mkdir($runtimePath)===false)
+ throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
+ @chmod($runtimePath, PRADO_CHMOD); }
+ $this->setConfigurationFile($configFile);
+ }
+ $this->setBasePath($basePath);
+ $this->setRuntimePath($runtimePath);
+ }
+ else
+ throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
+ }
+ public function run()
+ {
+ try
+ {
+ $this->initApplication();
+ $n=count(self::$_steps);
+ $this->_step=0;
+ $this->_requestCompleted=false;
+ while($this->_step<$n)
+ {
+ if($this->_mode===self::STATE_OFF)
+ throw new THttpException(503,'application_unavailable');
+ if($this->_requestCompleted)
+ break;
+ $method=self::$_steps[$this->_step];
+ $this->$method();
+ $this->_step++;
+ }
+ }
+ catch(Exception $e)
+ {
+ $this->onError($e);
+ }
+ $this->onEndRequest();
+ }
+ public function completeRequest()
+ {
+ $this->_requestCompleted=true;
+ }
+ public function getRequestCompleted()
+ {
+ return $this->_requestCompleted;
+ }
+ public function getGlobalState($key,$defaultValue=null)
+ {
+ return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
+ }
+ public function setGlobalState($key,$value,$defaultValue=null,$forceSave=false)
+ {
+ $this->_stateChanged=true;
+ if($value===$defaultValue)
+ unset($this->_globals[$key]);
+ else
+ $this->_globals[$key]=$value;
+ if($forceSave)
+ $this->saveGlobals();
+ }
+ public function clearGlobalState($key)
+ {
+ $this->_stateChanged=true;
+ unset($this->_globals[$key]);
+ }
+ protected function loadGlobals()
+ {
+ $this->_globals=$this->getApplicationStatePersister()->load();
+ }
+ protected function saveGlobals()
+ {
+ if($this->_stateChanged)
+ {
+ $this->_stateChanged=false;
+ $this->getApplicationStatePersister()->save($this->_globals);
+ }
+ }
+ public function getID()
+ {
+ return $this->_id;
+ }
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+ public function getPageServiceID()
+ {
+ return $this->_pageServiceID;
+ }
+ public function setPageServiceID($value)
+ {
+ $this->_pageServiceID=$value;
+ }
+ public function getUniqueID()
+ {
+ return $this->_uniqueID;
+ }
+ public function getMode()
+ {
+ return $this->_mode;
+ }
+ public function setMode($value)
+ {
+ $this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
+ }
+ public function getBasePath()
+ {
+ return $this->_basePath;
+ }
+ public function setBasePath($value)
+ {
+ $this->_basePath=$value;
+ }
+ public function getConfigurationFile()
+ {
+ return $this->_configFile;
+ }
+ public function setConfigurationFile($value)
+ {
+ $this->_configFile=$value;
+ }
+ public function getConfigurationType()
+ {
+ return $this->_configType;
+ }
+ public function setConfigurationType($value)
+ {
+ $this->_configType = $value;
+ }
+ public function getConfigurationFileExt()
+ {
+ if($this->_configFileExt===null)
+ {
+ switch($this->_configType)
+ {
+ case TApplication::CONFIG_TYPE_PHP:
+ $this->_configFileExt = TApplication::CONFIG_FILE_EXT_PHP;
+ break;
+ default:
+ $this->_configFileExt = TApplication::CONFIG_FILE_EXT_XML;
+ }
+ }
+ return $this->_configFileExt;
+ }
+ public function getConfigurationFileName()
+ {
+ static $fileName;
+ if($fileName == null)
+ {
+ switch($this->_configType)
+ {
+ case TApplication::CONFIG_TYPE_PHP:
+ $fileName = TApplication::CONFIG_FILE_PHP;
+ break;
+ default:
+ $fileName = TApplication::CONFIG_FILE_XML;
+ }
+ }
+ return $fileName;
+ }
+ public function getRuntimePath()
+ {
+ return $this->_runtimePath;
+ }
+ public function setRuntimePath($value)
+ {
+ $this->_runtimePath=$value;
+ if($this->_cacheFile)
+ $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
+ $this->_uniqueID=md5($this->_runtimePath);
+ }
+ public function getService()
+ {
+ return $this->_service;
+ }
+ public function setService($value)
+ {
+ $this->_service=$value;
+ }
+ public function setModule($id,IModule $module=null)
+ {
+ if(isset($this->_modules[$id]))
+ throw new TConfigurationException('application_moduleid_duplicated',$id);
+ else
+ $this->_modules[$id]=$module;
+ }
+ public function getModule($id)
+ {
+ if(!array_key_exists($id, $this->_modules))
+ return null;
+ if($this->_modules[$id]===null)
+ {
+ $module = $this->internalLoadModule($id, true);
+ $module[0]->init($module[1]);
+ }
+ return $this->_modules[$id];
+ }
+ public function getModules()
+ {
+ return $this->_modules;
+ }
+ public function getParameters()
+ {
+ return $this->_parameters;
+ }
+ public function getRequest()
+ {
+ if(!$this->_request)
+ {
+ $this->_request=new THttpRequest;
+ $this->_request->init(null);
+ }
+ return $this->_request;
+ }
+ public function setRequest(THttpRequest $request)
+ {
+ $this->_request=$request;
+ }
+ public function getResponse()
+ {
+ if(!$this->_response)
+ {
+ $this->_response=new THttpResponse;
+ $this->_response->init(null);
+ }
+ return $this->_response;
+ }
+ public function setResponse(THttpResponse $response)
+ {
+ $this->_response=$response;
+ }
+ public function getSession()
+ {
+ if(!$this->_session)
+ {
+ $this->_session=new THttpSession;
+ $this->_session->init(null);
+ }
+ return $this->_session;
+ }
+ public function setSession(THttpSession $session)
+ {
+ $this->_session=$session;
+ }
+ public function getErrorHandler()
+ {
+ if(!$this->_errorHandler)
+ {
+ $this->_errorHandler=new TErrorHandler;
+ $this->_errorHandler->init(null);
+ }
+ return $this->_errorHandler;
+ }
+ public function setErrorHandler(TErrorHandler $handler)
+ {
+ $this->_errorHandler=$handler;
+ }
+ public function getSecurityManager()
+ {
+ if(!$this->_security)
+ {
+ $this->_security=new TSecurityManager;
+ $this->_security->init(null);
+ }
+ return $this->_security;
+ }
+ public function setSecurityManager(TSecurityManager $sm)
+ {
+ $this->_security=$sm;
+ }
+ public function getAssetManager()
+ {
+ if(!$this->_assetManager)
+ {
+ $this->_assetManager=new TAssetManager;
+ $this->_assetManager->init(null);
+ }
+ return $this->_assetManager;
+ }
+ public function setAssetManager(TAssetManager $value)
+ {
+ $this->_assetManager=$value;
+ }
+ public function getApplicationStatePersister()
+ {
+ if(!$this->_statePersister)
+ {
+ $this->_statePersister=new TApplicationStatePersister;
+ $this->_statePersister->init(null);
+ }
+ return $this->_statePersister;
+ }
+ public function setApplicationStatePersister(IStatePersister $persister)
+ {
+ $this->_statePersister=$persister;
+ }
+ public function getCache()
+ {
+ return $this->_cache;
+ }
+ public function setCache(ICache $cache)
+ {
+ $this->_cache=$cache;
+ }
+ public function getUser()
+ {
+ return $this->_user;
+ }
+ public function setUser(IUser $user)
+ {
+ $this->_user=$user;
+ }
+ public function getGlobalization($createIfNotExists=true)
+ {
+ if($this->_globalization===null && $createIfNotExists)
+ {
+ $this->_globalization=new TGlobalization;
+ $this->_globalization->init(null);
+ }
+ return $this->_globalization;
+ }
+ public function setGlobalization(TGlobalization $glob)
+ {
+ $this->_globalization=$glob;
+ }
+ public function getAuthorizationRules()
+ {
+ if($this->_authRules===null)
+ $this->_authRules=new TAuthorizationRuleCollection;
+ return $this->_authRules;
+ }
+ protected function getApplicationConfigurationClass()
+ {
+ return 'TApplicationConfiguration';
+ }
+ protected function internalLoadModule($id, $force=false)
+ {
+ list($moduleClass, $initProperties, $configElement)=$this->_lazyModules[$id];
+ if(isset($initProperties['lazy']) && $initProperties['lazy'] && !$force)
+ {
+ $this->setModule($id, null);
+ return null;
+ }
+ $module=Prado::createComponent($moduleClass);
+ foreach($initProperties as $name=>$value)
+ {
+ if($name==='lazy') continue;
+ $module->setSubProperty($name,$value);
+ }
+ $this->setModule($id,$module);
+ $this->_lazyModules[$id]=null;
+ return array($module,$configElement);
+ }
+ public function applyConfiguration($config,$withinService=false)
+ {
+ if($config->getIsEmpty())
+ return;
+ foreach($config->getAliases() as $alias=>$path)
+ Prado::setPathOfAlias($alias,$path);
+ foreach($config->getUsings() as $using)
+ Prado::using($using);
+ if(!$withinService)
+ {
+ foreach($config->getProperties() as $name=>$value)
+ $this->setSubProperty($name,$value);
+ }
+ if(empty($this->_services))
+ $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
+ foreach($config->getParameters() as $id=>$parameter)
+ {
+ if(is_array($parameter))
+ {
+ $component=Prado::createComponent($parameter[0]);
+ foreach($parameter[1] as $name=>$value)
+ $component->setSubProperty($name,$value);
+ $this->_parameters->add($id,$component);
+ }
+ else
+ $this->_parameters->add($id,$parameter);
+ }
+ $modules=array();
+ foreach($config->getModules() as $id=>$moduleConfig)
+ {
+ if(!is_string($id))
+ $id='_module'.count($this->_lazyModules);
+ $this->_lazyModules[$id]=$moduleConfig;
+ if($module = $this->internalLoadModule($id))
+ $modules[]=$module;
+ }
+ foreach($modules as $module)
+ $module[0]->init($module[1]);
+ foreach($config->getServices() as $serviceID=>$serviceConfig)
+ $this->_services[$serviceID]=$serviceConfig;
+ foreach($config->getExternalConfigurations() as $filePath=>$condition)
+ {
+ if($condition!==true)
+ $condition=$this->evaluateExpression($condition);
+ if($condition)
+ {
+ if(($path=Prado::getPathOfNamespace($filePath,$this->getConfigurationFileExt()))===null || !is_file($path))
+ throw new TConfigurationException('application_includefile_invalid',$filePath);
+ $cn=$this->getApplicationConfigurationClass();
+ $c=new $cn;
+ $c->loadFromFile($path);
+ $this->applyConfiguration($c,$withinService);
+ }
+ }
+ }
+ protected function initApplication()
+ {
+ if($this->_configFile!==null)
+ {
+ if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
+ {
+ $config=new TApplicationConfiguration;
+ $config->loadFromFile($this->_configFile);
+ if($this->_cacheFile!==null)
+ file_put_contents($this->_cacheFile,serialize($config),LOCK_EX);
+ }
+ else
+ $config=unserialize(file_get_contents($this->_cacheFile));
+ $this->applyConfiguration($config,false);
+ }
+ if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
+ $serviceID=$this->getPageServiceID();
+ $this->startService($serviceID);
+ }
+ public function startService($serviceID)
+ {
+ if(isset($this->_services[$serviceID]))
+ {
+ list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
+ $service=Prado::createComponent($serviceClass);
+ if(!($service instanceof IService))
+ throw new THttpException(500,'application_service_invalid',$serviceClass);
+ if(!$service->getEnabled())
+ throw new THttpException(500,'application_service_unavailable',$serviceClass);
+ $service->setID($serviceID);
+ $this->setService($service);
+ foreach($initProperties as $name=>$value)
+ $service->setSubProperty($name,$value);
+ if($configElement!==null)
+ {
+ $config=new TApplicationConfiguration;
+ if($this->getConfigurationType()==self::CONFIG_TYPE_PHP)
+ $config->loadFromPhp($configElement,$this->getBasePath());
+ else
+ $config->loadFromXml($configElement,$this->getBasePath());
+ $this->applyConfiguration($config,true);
+ }
+ $service->init($configElement);
+ }
+ else
+ throw new THttpException(500,'application_service_unknown',$serviceID);
+ }
+ public function onError($param)
+ {
+ Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
+ $this->raiseEvent('OnError',$this,$param);
+ $this->getErrorHandler()->handleError($this,$param);
+ }
+ public function onBeginRequest()
+ {
+ $this->raiseEvent('OnBeginRequest',$this,null);
+ }
+ public function onAuthentication()
+ {
+ $this->raiseEvent('OnAuthentication',$this,null);
+ }
+ public function onAuthenticationComplete()
+ {
+ $this->raiseEvent('OnAuthenticationComplete',$this,null);
+ }
+ public function onAuthorization()
+ {
+ $this->raiseEvent('OnAuthorization',$this,null);
+ }
+ public function onAuthorizationComplete()
+ {
+ $this->raiseEvent('OnAuthorizationComplete',$this,null);
+ }
+ public function onLoadState()
+ {
+ $this->loadGlobals();
+ $this->raiseEvent('OnLoadState',$this,null);
+ }
+ public function onLoadStateComplete()
+ {
+ $this->raiseEvent('OnLoadStateComplete',$this,null);
+ }
+ public function onPreRunService()
+ {
+ $this->raiseEvent('OnPreRunService',$this,null);
+ }
+ public function runService()
+ {
+ if($this->_service)
+ $this->_service->run();
+ }
+ public function onSaveState()
+ {
+ $this->raiseEvent('OnSaveState',$this,null);
+ $this->saveGlobals();
+ }
+ public function onSaveStateComplete()
+ {
+ $this->raiseEvent('OnSaveStateComplete',$this,null);
+ }
+ public function onPreFlushOutput()
+ {
+ $this->raiseEvent('OnPreFlushOutput',$this,null);
+ }
+ public function flushOutput($continueBuffering = true)
+ {
+ $this->getResponse()->flush($continueBuffering);
+ }
+ public function onEndRequest()
+ {
+ $this->flushOutput(false); $this->saveGlobals(); $this->raiseEvent('OnEndRequest',$this,null);
+ }
+}
+class TApplicationMode extends TEnumerable
+{
+ const Off='Off';
+ const Debug='Debug';
+ const Normal='Normal';
+ const Performance='Performance';
+}
+class TApplicationConfiguration extends TComponent
+{
+ private $_properties=array();
+ private $_usings=array();
+ private $_aliases=array();
+ private $_modules=array();
+ private $_services=array();
+ private $_parameters=array();
+ private $_includes=array();
+ private $_empty=true;
+ public function loadFromFile($fname)
+ {
+ if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ $fcontent = include $fname;
+ $this->loadFromPhp($fcontent,dirname($fname));
+ }
+ else
+ {
+ $dom=new TXmlDocument;
+ $dom->loadFromFile($fname);
+ $this->loadFromXml($dom,dirname($fname));
+ }
+ }
+ public function getIsEmpty()
+ {
+ return $this->_empty;
+ }
+ public function loadFromPhp($config, $configPath)
+ {
+ if(isset($config['application']))
+ {
+ foreach($config['application'] as $name=>$value)
+ {
+ $this->_properties[$name]=$value;
+ }
+ $this->_empty = false;
+ }
+ if(isset($config['paths']) && is_array($config['paths']))
+ $this->loadPathsPhp($config['paths'],$configPath);
+ if(isset($config['modules']) && is_array($config['modules']))
+ $this->loadModulesPhp($config['modules'],$configPath);
+ if(isset($config['services']) && is_array($config['services']))
+ $this->loadServicesPhp($config['services'],$configPath);
+ if(isset($config['parameters']) && is_array($config['parameters']))
+ $this->loadParametersPhp($config['parameters'], $configPath);
+ if(isset($config['includes']) && is_array($config['includes']))
+ $this->loadExternalXml($config['includes'],$configPath);
+ }
+ public function loadFromXml($dom,$configPath)
+ {
+ foreach($dom->getAttributes() as $name=>$value)
+ {
+ $this->_properties[$name]=$value;
+ $this->_empty=false;
+ }
+ foreach($dom->getElements() as $element)
+ {
+ switch($element->getTagName())
+ {
+ case 'paths':
+ $this->loadPathsXml($element,$configPath);
+ break;
+ case 'modules':
+ $this->loadModulesXml($element,$configPath);
+ break;
+ case 'services':
+ $this->loadServicesXml($element,$configPath);
+ break;
+ case 'parameters':
+ $this->loadParametersXml($element,$configPath);
+ break;
+ case 'include':
+ $this->loadExternalXml($element,$configPath);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ protected function loadPathsPhp($pathsNode, $configPath)
+ {
+ if(isset($pathsNode['aliases']) && is_array($pathsNode['aliases']))
+ {
+ foreach($pathsNode['aliases'] as $id=>$path)
+ {
+ $path=str_replace('\\','/',$path);
+ if(preg_match('/^\\/|.:\\/|.:\\\\/',$path)) $p=realpath($path);
+ else
+ $p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
+ if($p===false || !is_dir($p))
+ throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
+ if(isset($this->_aliases[$id]))
+ throw new TConfigurationException('appconfig_alias_redefined',$id);
+ $this->_aliases[$id]=$p;
+ }
+ }
+ if(isset($pathsNode['using']) && is_array($pathsNode['using']))
+ {
+ foreach($pathsNode['using'] as $namespace)
+ {
+ $this->_usings[] = $namespace;
+ }
+ }
+ }
+ protected function loadPathsXml($pathsNode,$configPath)
+ {
+ foreach($pathsNode->getElements() as $element)
+ {
+ switch($element->getTagName())
+ {
+ case 'alias':
+ {
+ if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
+ {
+ $path=str_replace('\\','/',$path);
+ if(preg_match('/^\\/|.:\\/|.:\\\\/',$path)) $p=realpath($path);
+ else
+ $p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
+ if($p===false || !is_dir($p))
+ throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
+ if(isset($this->_aliases[$id]))
+ throw new TConfigurationException('appconfig_alias_redefined',$id);
+ $this->_aliases[$id]=$p;
+ }
+ else
+ throw new TConfigurationException('appconfig_alias_invalid');
+ $this->_empty=false;
+ break;
+ }
+ case 'using':
+ {
+ if(($namespace=$element->getAttribute('namespace'))!==null)
+ $this->_usings[]=$namespace;
+ else
+ throw new TConfigurationException('appconfig_using_invalid');
+ $this->_empty=false;
+ break;
+ }
+ default:
+ throw new TConfigurationException('appconfig_paths_invalid',$element->getTagName());
+ }
+ }
+ }
+ protected function loadModulesPhp($modulesNode, $configPath)
+ {
+ foreach($modulesNode as $id=>$module)
+ {
+ if(!isset($module['class']))
+ throw new TConfigurationException('appconfig_moduletype_required',$id);
+ $type = $module['class'];
+ unset($module['class']);
+ $properties = array();
+ if(isset($module['properties']))
+ {
+ $properties = $module['properties'];
+ unset($module['properties']);
+ }
+ $properties['id'] = $id;
+ $this->_modules[$id]=array($type,$properties,$module);
+ $this->_empty=false;
+ }
+ }
+ protected function loadModulesXml($modulesNode,$configPath)
+ {
+ foreach($modulesNode->getElements() as $element)
+ {
+ if($element->getTagName()==='module')
+ {
+ $properties=$element->getAttributes();
+ $id=$properties->itemAt('id');
+ $type=$properties->remove('class');
+ if($type===null)
+ throw new TConfigurationException('appconfig_moduletype_required',$id);
+ $element->setParent(null);
+ if($id===null)
+ $this->_modules[]=array($type,$properties->toArray(),$element);
+ else
+ $this->_modules[$id]=array($type,$properties->toArray(),$element);
+ $this->_empty=false;
+ }
+ else
+ throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
+ }
+ }
+ protected function loadServicesPhp($servicesNode,$configPath)
+ {
+ foreach($servicesNode as $id => $service)
+ {
+ if(!isset($service['class']))
+ throw new TConfigurationException('appconfig_servicetype_required');
+ $type = $service['class'];
+ $properties = isset($service['properties']) ? $service['properties'] : array();
+ unset($service['properties']);
+ $properties['id'] = $id;
+ $this->_services[$id] = array($type,$properties,$service);
+ $this->_empty = false;
+ }
+ }
+ protected function loadServicesXml($servicesNode,$configPath)
+ {
+ foreach($servicesNode->getElements() as $element)
+ {
+ if($element->getTagName()==='service')
+ {
+ $properties=$element->getAttributes();
+ if(($id=$properties->itemAt('id'))===null)
+ throw new TConfigurationException('appconfig_serviceid_required');
+ if(($type=$properties->remove('class'))===null)
+ throw new TConfigurationException('appconfig_servicetype_required',$id);
+ $element->setParent(null);
+ $this->_services[$id]=array($type,$properties->toArray(),$element);
+ $this->_empty=false;
+ }
+ else
+ throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
+ }
+ }
+ protected function loadParametersPhp($parametersNode,$configPath)
+ {
+ foreach($parametersNode as $id => $parameter)
+ {
+ if(is_array($parameter))
+ {
+ if(isset($parameter['class']))
+ {
+ $type = $parameter['class'];
+ unset($parameter['class']);
+ $properties = isset($service['properties']) ? $service['properties'] : array();
+ $properties['id'] = $id;
+ $this->_parameters[$id] = array($type,$properties);
+ }
+ }
+ else
+ {
+ $this->_parameters[$id] = $parameter;
+ }
+ }
+ }
+ protected function loadParametersXml($parametersNode,$configPath)
+ {
+ foreach($parametersNode->getElements() as $element)
+ {
+ if($element->getTagName()==='parameter')
+ {
+ $properties=$element->getAttributes();
+ if(($id=$properties->remove('id'))===null)
+ throw new TConfigurationException('appconfig_parameterid_required');
+ if(($type=$properties->remove('class'))===null)
+ {
+ if(($value=$properties->remove('value'))===null)
+ $this->_parameters[$id]=$element;
+ else
+ $this->_parameters[$id]=$value;
+ }
+ else
+ $this->_parameters[$id]=array($type,$properties->toArray());
+ $this->_empty=false;
+ }
+ else
+ throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
+ }
+ }
+ protected function loadExternalPhp($includeNode,$configPath)
+ {
+ foreach($includeNode as $include)
+ {
+ $when = isset($include['when'])?true:false;
+ if(!isset($include['file']))
+ throw new TConfigurationException('appconfig_includefile_required');
+ $filePath = $include['file'];
+ if(isset($this->_includes[$filePath]))
+ $this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
+ else
+ $$this->_includes[$filePath]=$when;
+ $this->_empty=false;
+ }
+ }
+ protected function loadExternalXml($includeNode,$configPath)
+ {
+ if(($when=$includeNode->getAttribute('when'))===null)
+ $when=true;
+ if(($filePath=$includeNode->getAttribute('file'))===null)
+ throw new TConfigurationException('appconfig_includefile_required');
+ if(isset($this->_includes[$filePath]))
+ $this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
+ else
+ $this->_includes[$filePath]=$when;
+ $this->_empty=false;
+ }
+ public function getProperties()
+ {
+ return $this->_properties;
+ }
+ public function getAliases()
+ {
+ return $this->_aliases;
+ }
+ public function getUsings()
+ {
+ return $this->_usings;
+ }
+ public function getModules()
+ {
+ return $this->_modules;
+ }
+ public function getServices()
+ {
+ return $this->_services;
+ }
+ public function getParameters()
+ {
+ return $this->_parameters;
+ }
+ public function getExternalConfigurations()
+ {
+ return $this->_includes;
+ }
+}
+class TApplicationStatePersister extends TModule implements IStatePersister
+{
+ const CACHE_NAME='prado:appstate';
+ public function init($config)
+ {
+ $this->getApplication()->setApplicationStatePersister($this);
+ }
+ protected function getStateFilePath()
+ {
+ return $this->getApplication()->getRuntimePath().'/global.cache';
+ }
+ public function load()
+ {
+ if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
+ return unserialize($value);
+ else
+ {
+ if(($content=@file_get_contents($this->getStateFilePath()))!==false)
+ return unserialize($content);
+ else
+ return null;
+ }
+ }
+ public function save($state)
+ {
+ $content=serialize($state);
+ $saveFile=true;
+ if(($cache=$this->getApplication()->getCache())!==null)
+ {
+ if($cache->get(self::CACHE_NAME)===$content)
+ $saveFile=false;
+ else
+ $cache->set(self::CACHE_NAME,$content);
+ }
+ if($saveFile)
+ {
+ $fileName=$this->getStateFilePath();
+ file_put_contents($fileName,$content,LOCK_EX);
+ }
+ }
+}
+class TShellApplication extends TApplication
+{
+ public function run()
+ {
+ $this->initApplication();
+ }
+}
+?> \ No newline at end of file