diff options
author | emkael <emkael@tlen.pl> | 2016-02-24 23:18:07 +0100 |
---|---|---|
committer | emkael <emkael@tlen.pl> | 2016-02-24 23:18:07 +0100 |
commit | 6f7fdef0f500cd4bb540affd3bc1482243f337c1 (patch) | |
tree | 4853eecd0769a903e6130c1896e1d070848150dd /lib/prado/framework/pradolite.php | |
parent | 61f2ea48a4e11cb5fb941b3783e19c9e9ef38a45 (diff) |
* Prado 3.3.0
Diffstat (limited to 'lib/prado/framework/pradolite.php')
-rw-r--r-- | lib/prado/framework/pradolite.php | 11236 |
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( + '>'=>'>', + '<'=>'<', + '&'=>'&', + '"'=>'"', + "\r"=>'
', + "\t"=>'	', + "\n"=>'
')); + } +} +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('<'=>'<','>'=>'>','"'=>'"'); + private static $_decodeTable=array('<'=>'<','>'=>'>','"'=>'"'); + private static $_stripTable=array('<'=>'','>'=>'','"'=>''); + 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?'&':'&'; + $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?'&':'&')) . 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('&','&',$url), true, $this->_status); + else + header('Location: '.str_replace('&','&',$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('&','&',str_replace('&','&',$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 |