From a5d7da29b3b5c1de6301950a8ca3e3e19e022ba0 Mon Sep 17 00:00:00 2001
From: "Christophe.Boulain" <>
Date: Mon, 11 Jan 2010 12:58:38 +0000
Subject: Issue#218 : Changed URL of Javascript Logger to the archived page
---
.gitattributes | 1 +
HISTORY | 1 +
.../protected/pages/Controls/JavascriptLogger.page | 2 +-
.../pages/Controls/id/JavascriptLogger.page | 2 +-
framework/3rdParty/readme.html | 2 +-
framework/Web/UI/WebControls/TJavascriptLogger.php | 6 +-
framework/pradolite.php | 9489 ++++++++++++++++++++
7 files changed, 9497 insertions(+), 6 deletions(-)
create mode 100644 framework/pradolite.php
diff --git a/.gitattributes b/.gitattributes
index 772a2b7d..31cdc4d7 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2734,6 +2734,7 @@ framework/powered2.gif -text
framework/prado-cli -text
framework/prado-cli.bat -text
framework/prado.php -text
+framework/pradolite.php -text
/index.html -text
/phing -text
/phing.bat -text
diff --git a/HISTORY b/HISTORY
index 8c9f71a5..6c4465f7 100644
--- a/HISTORY
+++ b/HISTORY
@@ -13,6 +13,7 @@ BUG: Typo in TBoundColumn (Robin)
ENH: Add property ClientScriptManagerClass to TPageService and releated changes in TPage.getClientScript() (Yves)
ENH: Always render clientside counterparts of validation control even if not enabled, but pass-through Enabled property, to allow Enabled/Disable of validator on callback. (Yves)
EHN: Add property TValidationSummary.ScrollToSummary to server-side control since property exists on client-side. (Yves)
+CHG: Issue#218 - Change URL of Javascript Logger (Christophe)
Version 3.1.6 July 22, 2009
BUG: Issue#98 - Missing file in quickstart demo (Chrisotphe)
diff --git a/demos/quickstart/protected/pages/Controls/JavascriptLogger.page b/demos/quickstart/protected/pages/Controls/JavascriptLogger.page
index 3c7d0684..c2187632 100644
--- a/demos/quickstart/protected/pages/Controls/JavascriptLogger.page
+++ b/demos/quickstart/protected/pages/Controls/JavascriptLogger.page
@@ -4,7 +4,7 @@
-TJavascriptLogger provides logging for client-side javascript. It is mainly a wrapper of the Javascript developed at http://gleepglop.com/javascripts/logger/ .
+TJavascriptLogger provides logging for client-side javascript. It is mainly a wrapper of the Javascript developed at http://gleepglop.com/javascripts/logger/ .
diff --git a/demos/quickstart/protected/pages/Controls/id/JavascriptLogger.page b/demos/quickstart/protected/pages/Controls/id/JavascriptLogger.page
index 93be7d9b..4fb52ee5 100644
--- a/demos/quickstart/protected/pages/Controls/id/JavascriptLogger.page
+++ b/demos/quickstart/protected/pages/Controls/id/JavascriptLogger.page
@@ -4,7 +4,7 @@
-TJavascriptLogger menyediakan javascript pencatatan sisi-klien. Ini sebagian besar adalah pelapis dari Javascript yang dikembangkan di http://gleepglop.com/javascripts/logger/ .
+TJavascriptLogger menyediakan javascript pencatatan sisi-klien. Ini sebagian besar adalah pelapis dari Javascript yang dikembangkan di http://gleepglop.com/javascripts/logger/ .
diff --git a/framework/3rdParty/readme.html b/framework/3rdParty/readme.html
index bf9c243f..a25ec97a 100644
--- a/framework/3rdParty/readme.html
+++ b/framework/3rdParty/readme.html
@@ -99,7 +99,7 @@ projects.
../Web/Javascripts/prado/logger/logger.js
- http://gleepglop.com/javascripts/logger/ http://slayeroffice.com
+ http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/ http://slayeroffice.com
None
TJavascriptLogger
Javascript logger by Corey Johnson. Object Tree by S.G. Chipman.
diff --git a/framework/Web/UI/WebControls/TJavascriptLogger.php b/framework/Web/UI/WebControls/TJavascriptLogger.php
index 6d49f801..778b6728 100644
--- a/framework/Web/UI/WebControls/TJavascriptLogger.php
+++ b/framework/Web/UI/WebControls/TJavascriptLogger.php
@@ -4,7 +4,7 @@
*
* @author Wei Zhuo
* @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2008 PradoSoft
+ * @copyright Copyright © 2005-2008 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Web.UI.WebControls
@@ -23,7 +23,7 @@
*
* To see the logger and console, press ALT-D (or CTRL-D on OS X).
* More information on the logger can be found at
- * http://gleepglop.com/javascripts/logger/
+ * http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/
*
* @author Wei Zhuo
* @version $Id$
@@ -84,7 +84,7 @@ class TJavascriptLogger extends TWebControl
public function renderContents($writer)
{
$code = strtoupper($this->getToggleKey());
- $info = '(more info ).';
+ $info = '(more info ).';
$link = 'toggle the javascript log console. ';
$usage = 'Press ALT-'.$code.' (Or CTRL-'.$code.' on OS X) to';
$writer->write("{$usage} {$link} {$info}");
diff --git a/framework/pradolite.php b/framework/pradolite.php
new file mode 100644
index 00000000..6d5b13fd
--- /dev/null
+++ b/framework/pradolite.php
@@ -0,0 +1,9489 @@
+PRADO_DIR);
+ private static $_usings=array();
+ private static $_application=null;
+ private static $_logger=null;
+ public static function getVersion()
+ {
+ return '3.1.6-dev';
+ }
+ public static function initErrorHandlers()
+ {
+ set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting());
+ 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://www.pradosoft.com/images/'.$logoName.'.gif';
+ return ' ';
+ }
+ public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
+ {
+ if(error_reporting()!=0)
+ 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)
+ 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 serialize($data)
+ {
+ $arr[0]=$data;
+ return serialize($arr);
+ }
+ public static function unserialize($str)
+ {
+ $arr=unserialize($str);
+ return isset($arr[0])?$arr[0]:null;
+ }
+ public static function createComponent($type)
+ {
+ self::using($type);
+ if(($pos=strrpos($type,'.'))!==false)
+ $type=substr($type,$pos+1);
+ if(($n=func_num_args())>1)
+ {
+ $args=func_get_args();
+ $s='$args[1]';
+ for($i=2;$i<$n;++$i)
+ $s.=",\$args[$i]";
+ eval("\$component=new $type($s);");
+ return $component;
+ }
+ 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(isset(self::$_usings[$namespace]))
+ return self::$_usings[$namespace];
+ else if(isset(self::$_aliases[$namespace]))
+ return self::$_aliases[$namespace];
+ else
+ {
+ $segs=explode('.',$namespace);
+ $alias=array_shift($segs);
+ if(($file=array_pop($segs))!==null && ($root=self::getPathOfAlias($alias))!==null)
+ return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file==='*')?'':DIRECTORY_SEPARATOR.$file.$ext);
+ else
+ 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]))
+ 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 'Fatal Error ';
+ echo ''.$msg.'
';
+ if(!function_exists('debug_backtrace'))
+ return;
+ echo 'Debug Backtrace ';
+ echo '';
+ $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 '';
+ 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 ' ';
+ 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')
+ {
+ 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);
+ }
+ public static function log($msg,$level=TLogger::INFO,$category='Uncategorized')
+ {
+ if(self::$_logger===null)
+ self::$_logger=new TLogger;
+ self::$_logger->log($msg,$level,$category);
+ }
+ 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);
+ }
+}
+class TReflectionClass extends ReflectionClass
+{
+}
+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)
+ {
+ return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath);
+ }
+}
+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 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']:'';
+ if($this->getApplication()->getMode()===TApplicationMode::Debug)
+ $version=$_SERVER['SERVER_SOFTWARE'].' PRADO /'.Prado::getVersion();
+ else
+ $version='';
+ $tokens=array(
+ '%%StatusCode%%' => "$statusCode",
+ '%%ErrorMessage%%' => htmlspecialchars($exception->getMessage()),
+ '%%ServerAdmin%%' => $serverAdmin,
+ '%%Version%%' => $version,
+ '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
+ );
+ header("HTTP/1.0 $statusCode ".$exception->getMessage());
+ echo strtr($content,$tokens);
+ }
+ protected function handleRecursiveError($exception)
+ {
+ if($this->getApplication()->getMode()===TApplicationMode::Debug)
+ {
+ echo "Recursive Error \n";
+ echo "Recursive Error \n";
+ echo "".$exception->__toString()." \n";
+ echo "";
+ }
+ 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'].' PRADO /'.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.="".$line."
";
+ }
+ else
+ $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
+ }
+ return $source;
+ }
+ private function addLink($message)
+ {
+ $baseUrl='http://www.pradosoft.com/docs/classdoc';
+ return preg_replace('/\b(T[A-Z]\w+)\b/',"\${1} ",$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 TListIterator($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(($index=$this->indexOf($item))>=0)
+ {
+ $this->removeAt($index);
+ return $index;
+ }
+ else
+ throw new TInvalidDataValueException('list_item_inexistent');
+ }
+ 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 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(($value=$this->getValue($this->generateUniqueKey($id)))!==false)
+ {
+ $data=unserialize($value);
+ 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),serialize($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),serialize($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 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 TMapIterator($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 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 TStackIterator($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=$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,$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 "\n".$this->toString(0);
+ }
+ public function __toString()
+ {
+ return $this->saveToString();
+ }
+ private 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 $_validation=TSecurityManagerValidationMode::SHA1;
+ private $_encryption='3DES';
+ public function init($config)
+ {
+ $this->getApplication()->setSecurityManager($this);
+ }
+ protected function generateRandomKey()
+ {
+ return rand().rand().rand().rand();
+ }
+ public function getValidationKey()
+ {
+ if($this->_validationKey===null)
+ {
+ if(($this->_validationKey=$this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))===null)
+ {
+ $this->_validationKey=$this->generateRandomKey();
+ $this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY,$this->_validationKey,null);
+ }
+ }
+ return $this->_validationKey;
+ }
+ public function setValidationKey($value)
+ {
+ if($value!=='')
+ $this->_validationKey=$value;
+ else
+ throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
+ }
+ public function getEncryptionKey()
+ {
+ if($this->_encryptionKey===null)
+ {
+ if(($this->_encryptionKey=$this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))===null)
+ {
+ $this->_encryptionKey=$this->generateRandomKey();
+ $this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY,$this->_encryptionKey,null);
+ }
+ }
+ return $this->_encryptionKey;
+ }
+ public function setEncryptionKey($value)
+ {
+ if($value!=='')
+ $this->_encryptionKey=$value;
+ else
+ throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
+ }
+ public function getValidation()
+ {
+ return $this->_validation;
+ }
+ public function setValidation($value)
+ {
+ $this->_validation=TPropertyValue::ensureEnum($value,'TSecurityManagerValidationMode');
+ }
+ public function getEncryption()
+ {
+ return $this->_encryption;
+ }
+ public function setEncryption($value)
+ {
+ throw new TNotSupportedException('Currently only 3DES encryption is supported');
+ }
+ public function encrypt($data)
+ {
+ if(function_exists('mcrypt_encrypt'))
+ {
+ $module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
+ $key=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;
+ }
+ else
+ throw new TNotSupportedException('securitymanager_mcryptextension_required');
+ }
+ public function decrypt($data)
+ {
+ if(function_exists('mcrypt_decrypt'))
+ {
+ $module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
+ $key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module));
+ $ivSize=mcrypt_enc_get_iv_size($module);
+ $iv=substr($data,0,$ivSize);
+ mcrypt_generic_init($module,$key,$iv);
+ $decrypted=mdecrypt_generic($module,substr($data,$ivSize));
+ mcrypt_generic_deinit($module);
+ mcrypt_module_close($module);
+ return rtrim($decrypted,"\0");
+ }
+ else
+ throw new TNotSupportedException('securitymanager_mcryptextension_required');
+ }
+ public function hashData($data)
+ {
+ $hmac=$this->computeHMAC($data);
+ return $hmac.$data;
+ }
+ public function validateData($data)
+ {
+ $len=$this->_validation==='SHA1'?40:32;
+ if(strlen($data)>=$len)
+ {
+ $hmac=substr($data,0,$len);
+ $data2=substr($data,$len);
+ return $hmac===$this->computeHMAC($data2)?$data2:false;
+ }
+ else
+ return false;
+ }
+ protected function computeHMAC($data)
+ {
+ if($this->_validation==='SHA1')
+ {
+ $pack='H40';
+ $func='sha1';
+ }
+ else
+ {
+ $pack='H32';
+ $func='md5';
+ }
+ $key=$this->getValidationKey();
+ $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)));
+ }
+}
+class TSecurityManagerValidationMode extends TEnumerable
+{
+ const MD5='MD5';
+ const SHA1='SHA1';
+}
+class THttpUtility
+{
+ private static $_encodeTable=array('<'=>'<','>'=>'>','"'=>'"');
+ private static $_decodeTable=array('<'=>'<','>'=>'>','"'=>'"');
+ public static function htmlEncode($s)
+ {
+ return strtr($s,self::$_encodeTable);
+ }
+ public static function htmlDecode($s)
+ {
+ return strtr($s,self::$_decodeTable);
+ }
+}
+class TJavaScript
+{
+ private static $_json;
+ public static function renderScriptFiles($files)
+ {
+ $str='';
+ foreach($files as $file)
+ $str.= self::renderScriptFile($file);
+ return $str;
+ }
+ public static function renderScriptFile($file)
+ {
+ return '\n";
+ }
+ public static function renderScriptBlocks($scripts)
+ {
+ if(count($scripts))
+ return "\n";
+ else
+ return '';
+ }
+ public static function renderScriptBlock($script)
+ {
+ return "\n";
+ }
+ public static function quoteString($js,$forUrl=false)
+ {
+ if($forUrl)
+ return strtr($js,array('%'=>'%25',"\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
+ else
+ return strtr($js,array("\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
+ }
+ public static function quoteFunction($js)
+ {
+ if(self::isFunction($js))
+ return $js;
+ else
+ return 'javascript:'.$js;
+ }
+ public static function isFunction($js)
+ {
+ return preg_match('/^\s*javascript:/i', $js);
+ }
+ public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
+ {
+ if(is_string($value))
+ {
+ if(($n=strlen($value))>2)
+ {
+ $first=$value[0];
+ $last=$value[$n-1];
+ if(($first==='[' && $last===']') || ($first==='{' && $last==='}'))
+ return $value;
+ }
+ if(self::isFunction($value))
+ return preg_replace('/^\s*javascript:/', '', $value);
+ else
+ 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))
+ {
+ if($value===-INF)
+ return 'Number.NEGATIVE_INFINITY';
+ else if($value===INF)
+ return 'Number.POSITIVE_INFINITY';
+ else
+ return "$value";
+ }
+ else if(is_object($value))
+ return self::encode(get_object_vars($value),$toMap);
+ else if($value===null)
+ return 'null';
+ else
+ return '';
+ }
+ public static function jsonEncode($value)
+ {
+ if(self::$_json === null)
+ self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON');
+ return self::$_json->encode($value);
+ }
+ public static function jsonDecode($value)
+ {
+ if(self::$_json === null)
+ self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON');
+ return self::$_json->decode($value);
+ }
+}
+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;
+ }
+ }
+ }
+ if($request->getUrlFormat()===THttpRequestUrlFormat::Path)
+ return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
+ else
+ return $request->getApplicationUrl().'?'.$url;
+ }
+ public function parseUrl()
+ {
+ $request=$this->getRequest();
+ $pathInfo=trim($request->getPathInfo(),'/');
+ if($request->getUrlFormat()===THttpRequestUrlFormat::Path && $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
+{
+ private $_urlManager=null;
+ private $_urlManagerID='';
+ private $_separator=',';
+ private $_serviceID=null;
+ private $_serviceParam=null;
+ private $_cookies=null;
+ private $_requestUri;
+ private $_pathInfo;
+ private $_cookieOnly=false;
+ private $_urlFormat=THttpRequestUrlFormat::Get;
+ private $_services;
+ private $_requestResolved=false;
+ private $_enableCookieValidation=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(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);
+ }
+ 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']='';
+ }
+ $this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
+ if(isset($_SERVER['REQUEST_URI']))
+ $this->_requestUri=$_SERVER['REQUEST_URI'];
+ else $this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
+ if(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 getUrlManager()
+ {
+ return $this->_urlManagerID;
+ }
+ public function setUrlManager($value)
+ {
+ $this->_urlManagerID=$value;
+ }
+ public function getUrlManagerModule()
+ {
+ 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 $_SERVER['REQUEST_METHOD'];
+ }
+ 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']:'';
+ }
+ public function getHttpProtocolVersion ()
+ {
+ return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:'';
+ }
+ public function getRequestUri()
+ {
+ return $this->_requestUri;
+ }
+ public function getBaseUrl($forceSecureConnection=false)
+ {
+ $url=$this->getUrl();
+ $scheme=($forceSecureConnection)?"https":$url->getScheme();
+ $host=$url->getHost();
+ if (($port=$url->getPort())) $host.=':'.$port;
+ return $scheme.'://'.$host;
+ }
+ public function getApplicationUrl()
+ {
+ return $_SERVER['SCRIPT_NAME'];
+ }
+ public function getAbsoluteApplicationUrl($forceSecureConnection=false)
+ {
+ return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
+ }
+ public function getApplicationFilePath()
+ {
+ return realpath($_SERVER['SCRIPT_FILENAME']);
+ }
+ public function getServerName()
+ {
+ return $_SERVER['SERVER_NAME'];
+ }
+ public function getServerPort()
+ {
+ return $_SERVER['SERVER_PORT'];
+ }
+ 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 $_SERVER['HTTP_USER_AGENT'];
+ }
+ public function getUserHostAddress()
+ {
+ return $_SERVER['REMOTE_ADDR'];
+ }
+ public function getUserHost()
+ {
+ return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
+ }
+ public function getAcceptTypes()
+ {
+ return $_SERVER['HTTP_ACCEPT'];
+ }
+ public function getUserLanguages()
+ {
+ return Prado::getUserLanguages();
+ }
+ public function getEnableCookieValidation()
+ {
+ return $this->_enableCookieValidation;
+ }
+ public function setEnableCookieValidation($value)
+ {
+ $this->_enableCookieValidation=TPropertyValue::ensureBoolean($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)
+ {
+ $url=$this->_urlManager->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->_urlManager->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;
+ 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 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';
+}
+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
+{
+ 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;
+ 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)
+ {
+ $this->_contentType = $type;
+ }
+ public function getContentType()
+ {
+ return $this->_contentType;
+ }
+ public function getCharset()
+ {
+ return $this->_charset;
+ }
+ public function setCharset($charset)
+ {
+ $this->_charset = $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)
+ {
+ $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)
+ {
+ echo $str;
+ }
+ public function writeFile($fileName,$content=null,$mimeType=null,$headers=null)
+ {
+ static $defaultMimeTypes=array(
+ 'css'=>'text/css',
+ 'gif'=>'image/gif',
+ '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];
+ }
+ }
+ $fn=basename($fileName);
+ $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");
+ header('Content-Length: '.($content===null?filesize($fileName):strlen($content)));
+ header("Content-Disposition: attachment; filename=\"$fn\"");
+ 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)
+ {
+ if(!$this->getApplication()->getRequestCompleted())
+ $this->getApplication()->onEndRequest();
+ 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));
+ exit();
+ }
+ public function reload()
+ {
+ $this->redirect($this->getRequest()->getRequestUri());
+ }
+ public function flush()
+ {
+ if($this->getHasAdapter())
+ $this->_adapter->flushContent();
+ else
+ $this->flushContent();
+ }
+ public function flushContent()
+ {
+ $this->sendHttpHeader();
+ $this->sendContentTypeHeader();
+ if($this->_bufferOutput)
+ ob_flush();
+ }
+ protected function sendHttpHeader ()
+ {
+ if (($version=$this->getRequest()->getHttpProtocolVersion())==='')
+ header (' ', true, $this->_status);
+ else
+ header($version.' '.$this->_status.' '.$this->_reason, true, $this->_status);
+ }
+ protected function sendContentTypeHeader()
+ {
+ $charset=$this->getCharset();
+ if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
+ $charset=$globalization->getCharset();
+ if($charset!=='')
+ {
+ $contentType=$this->_contentType===null?'text/html':$this->_contentType;
+ $this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
+ }
+ else if($this->_contentType!==null)
+ $this->appendHeader('Content-Type: '.$this->_contentType.';charset=UTF-8');
+ }
+ public function getContents()
+ {
+ return $this->_bufferOutput?ob_get_contents():'';
+ }
+ public function clear()
+ {
+ if($this->_bufferOutput)
+ ob_clean();
+ }
+ public function appendHeader($value)
+ {
+ header($value);
+ }
+ 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());
+ }
+ else
+ setcookie($cookie->getName(),$cookie->getValue(),$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());
+ }
+ public function removeCookie($cookie)
+ {
+ setcookie($cookie->getName(),null,0,$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());
+ }
+ 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());
+ 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 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');
+ 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');
+ }
+ }
+ }
+ 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
+ ini_set('session.use_trans_sid',TPropertyValue::ensureBoolean($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::hasProperty($name);
+ }
+ public function canGetProperty($name)
+ {
+ return $this->contains($name) || parent::canGetProperty($name);
+ }
+ public function canSetProperty($name)
+ {
+ return true;
+ }
+}
+class TControlAdapter extends TApplicationComponent
+{
+ private $_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 __construct()
+ {
+ }
+ 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 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_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_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_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->addToPostDataLoader();
+ }
+ $this->_stage=self::CS_PRERENDERED;
+ }
+ protected function addToPostDataLoader()
+ {
+ if($this instanceof IPostBackDataHandler)
+ $this->getPage()->registerPostDataLoader($this);
+ }
+ 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->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 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);
+ 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 TWebControl extends TControl implements IStyleable
+{
+ 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);
+ }
+ protected function addAttributesToRender($writer)
+ {
+ if($this->getID()!=='')
+ $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)
+ {
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag($this->getTagName());
+ }
+ public function renderContents($writer)
+ {
+ parent::renderChildren($writer);
+ }
+ public function renderEndTag($writer)
+ {
+ $writer->renderEndTag();
+ }
+}
+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);
+ }
+}
+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();
+ $page->beginFormRender($writer);
+ $textWriter=new TTextWriter;
+ $this->renderChildren(new THtmlWriter($textWriter));
+ $content=$textWriter->flush();
+ $page->endFormRender($writer);
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag('form');
+ $cs=$page->getClientScript();
+ if($page->getClientSupportsJavaScript())
+ {
+ $cs->renderHiddenFields($writer);
+ $cs->renderScriptFiles($writer);
+ $cs->renderBeginScripts($writer);
+ $writer->write($content);
+ $cs->renderEndScripts($writer);
+ }
+ else
+ {
+ $cs->renderHiddenFields($writer);
+ $writer->write($content);
+ }
+ $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 SCRIPT_LOADER='Web/Javascripts/clientscripts.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;
+ 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 function registerPradoScript($name)
+ {
+ $this->registerPradoScriptInternal($name);
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
+ }
+ private function registerPradoScriptInternal($name)
+ {
+ if(!isset($this->_registeredPradoScripts[$name]))
+ {
+ if(self::$_pradoScripts === null)
+ {
+ $packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH.'/packages.php';
+ 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);
+ }
+ }
+ public function getPradoScriptAssetUrl()
+ {
+ $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
+ $assets = Prado::getApplication()->getAssetManager();
+ return $assets->getPublishedUrl($base);
+ }
+ protected function renderPradoScripts($writer)
+ {
+ if(($packages=array_keys($this->_registeredPradoScripts))!==array())
+ {
+ if (Prado::getApplication()->getMode()!==TApplicationMode::Debug)
+ {
+ $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
+ $url = $this->registerJavascriptPackages($base, $packages);
+ $writer->write(TJavaScript::renderScriptFile($url));
+ }
+ else
+ {
+ $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
+ list($path,$baseUrl)=$this->getPackagePathUrl($base);
+ $packagesUrl=array();
+ foreach ($packages as $p)
+ {
+ foreach (self::$_pradoScripts[$p] as $dep)
+ {
+ foreach (self::$_pradoPackages[$dep] as $script)
+ {
+ if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
+ $packagesUrl[]=$url;
+ }
+ }
+ }
+ $writer->write(TJavaScript::renderScriptFiles($packagesUrl));
+ }
+ }
+ }
+ public function registerJavascriptPackages($base, $packages, $debug=null, $gzip=true)
+ {
+ list($path,$url) = $this->getPackagePathUrl($base);
+ $scriptLoaderPath = $path.'/'.basename(self::SCRIPT_LOADER);
+ $scriptLoaderSrc = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_LOADER;
+ if(!is_file($scriptLoaderPath))
+ {
+ copy($scriptLoaderSrc, $scriptLoaderPath);
+ chmod($scriptLoaderPath, PRADO_CHMOD);
+ }
+ $url .= '/'.basename(self::SCRIPT_LOADER).'?js='.implode(',', $packages);
+ if($debug!==false && $this->getApplication()->getMode()===TApplicationMode::Debug)
+ {
+ $this->verifyJavascriptPackages($base,$path,$packages);
+ $url.='&mode=debug';
+ }
+ if($gzip===false)
+ $url.='&gzip=false';
+ return $url;
+ }
+ protected function verifyJavascriptPackages($base,$path,$scripts)
+ {
+ $file = $path.'/packages.php';
+ if(is_file($file))
+ {
+ list($packs,$deps) = include($file);
+ if(count($missing = array_diff($scripts, array_keys($deps))) > 0)
+ {
+ throw new TConfigurationException('csmanager_invalid_packages',
+ $base.'/packages.php',implode(', ', $missing), implode(', ', array_keys($deps)));
+ }
+ }
+ }
+ 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 TReflectionClass($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->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]='';
+ $this->_hiddenFields[TPage::FIELD_POSTBACK_PARAMETER]='';
+ $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->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]='';
+ $this->registerPradoScriptInternal('prado');
+ $params=array($panelID,$buttonID);
+ $this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
+ }
+ protected function getDefaultButtonOptions($panelID, $buttonID)
+ {
+ $options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
+ $options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
+ $options['EventTarget'] = $buttonID;
+ $options['Event'] = 'click';
+ return $options;
+ }
+ public function registerFocusControl($target)
+ {
+ $this->registerPradoScriptInternal('effects');
+ if($target instanceof TControl)
+ $target=$target->getClientID();
+ $id = TJavaScript::quoteString($target);
+ $this->_endScripts['prado:focus'] = 'new Effect.ScrollTo("'.$id.'"); Prado.Element.focus("'.$id.'");';
+ $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 registerHeadScriptFile($key,$url)
+ {
+ $this->_headScriptFiles[$key]=$url;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
+ }
+ public function registerHeadScript($key,$script)
+ {
+ $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->_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.=" \n";
+ else
+ $str.=" \n";
+ }
+ $writer->write($str);
+ }
+ public function renderStyleSheets($writer)
+ {
+ if(count($this->_styleSheets))
+ $writer->write("\n");
+ }
+ public function renderHeadScriptFiles($writer)
+ {
+ $writer->write(TJavaScript::renderScriptFiles($this->_headScriptFiles));
+ }
+ public function renderHeadScripts($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
+ }
+ public function renderScriptFiles($writer)
+ {
+ $this->renderPradoScripts($writer);
+ if(!empty($this->_scriptFiles))
+ $writer->write(TJavaScript::renderScriptFiles($this->_scriptFiles));
+ }
+ public function renderBeginScripts($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
+ }
+ public function renderEndScripts($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
+ }
+ public function renderHiddenFields($writer)
+ {
+ $str='';
+ foreach($this->_hiddenFields as $name=>$value)
+ {
+ $id=strtr($name,':','_');
+ if(is_array($value))
+ {
+ foreach($value as $v)
+ $str.=' \n";
+ }
+ else
+ {
+ $str.=' \n";
+ }
+ }
+ if($str!=='')
+ $writer->write("\n".$str."
\n");
+ }
+}
+abstract class TClientSideOptions extends TComponent
+{
+ private $_options;
+ public function __construct()
+ {
+ $this->_options = Prado::createComponent('System.Collections.TMap');
+ }
+ protected function setFunction($name, $code)
+ {
+ if(!TJavaScript::isFunction($code))
+ $code = TJavaScript::quoteFunction($this->ensureFunction($code));
+ $this->setOption($name, $code);
+ }
+ protected function getOption($name)
+ {
+ return $this->_options->itemAt($name);
+ }
+ protected function setOption($name, $value)
+ {
+ $this->_options->add($name, $value);
+ }
+ public function getOptions()
+ {
+ 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;
+ private $_postData;
+ private $_restPostData;
+ private $_controlsPostDataChanged=array();
+ private $_controlsRequiringPostData=array();
+ private $_controlsRegisteredForPostData=array();
+ private $_postBackEventTarget;
+ private $_postBackEventParameter;
+ private $_formRendered=false;
+ private $_inFormRender=false;
+ private $_focus;
+ private $_pagePath='';
+ private $_enableStateValidation=true;
+ private $_enableStateEncryption=false;
+ private $_statePersisterClass='System.Web.UI.TPageStatePersister';
+ private $_statePersister;
+ private $_cachingStack;
+ private $_clientState='';
+ private $_postDataLoaders=array();
+ private $_isLoadingPostData=false;
+ private $_enableJavaScript=true;
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setPage($this);
+ }
+ public function run($writer)
+ {
+ $this->determinePostBackMode();
+ if($this->getIsPostBack())
+ {
+ if($this->getIsCallback())
+ $this->processCallbackRequest($writer);
+ else
+ $this->processPostBackRequest($writer);
+ }
+ else
+ $this->processNormalRequest($writer);
+ }
+ 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 function processCallbackRequest($writer)
+ {
+ Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
+ $this->setAdapter(new TActivePageAdapter($this));
+ if (($g=$this->getApplication()->getGlobalization(false))!==null &&
+ strtoupper($enc=$g->getCharset())!='UTF-8')
+ foreach ($this->_postData as $k=>$v)
+ $this->_postData[$k]=iconv('UTF-8',$enc.'//IGNORE',$v);
+ $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 registerPostDataLoader($control)
+ {
+ $id=is_string($control)?$control:$control->getUniqueID();
+ $this->_postDataLoaders[$id] = true;
+ }
+ public function getPostDataLoaders()
+ {
+ return array_keys($this->_postDataLoaders);
+ }
+ 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($validationGroup===null)
+ 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)
+ $this->_clientScript=new TClientScriptManager($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;
+ $this->registerPostDataLoader($id);
+ $params=func_get_args();
+ foreach($this->getCachingStack() as $item)
+ $item->registerAction('Page','registerRequiresPostData',$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;
+ }
+ private function raiseChangedEvents()
+ {
+ foreach($this->_controlsPostDataChanged as $control)
+ $control->raisePostDataChangedEvent();
+ }
+ private function raisePostBackEvent()
+ {
+ if(($postBackHandler=$this->getPostBackEventTarget())===null)
+ $this->validate();
+ else if($postBackHandler instanceof IPostBackEventHandler)
+ $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
+ }
+ public function ensureRenderInForm($control)
+ {
+ if(!$this->getIsCallback() && !$this->_inFormRender)
+ throw new TConfigurationException('page_control_outofform',get_class($control),$control->getUniqueID());
+ }
+ public function beginFormRender($writer)
+ {
+ if($this->_formRendered)
+ throw new TConfigurationException('page_form_duplicated');
+ $this->_formRendered=true;
+ $this->_inFormRender=true;
+ $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
+ }
+ 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 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;
+ }
+}
+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(Prado::serialize($data));
+ else
+ $str=Prado::serialize($data);
+ if(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(extension_loaded('zlib'))
+ $str=@gzuncompress($str);
+ if($page->getEnableStateValidation())
+ {
+ if(($str=$sm->validateData($str))!==false)
+ return Prado::unserialize($str);
+ }
+ else
+ return $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);
+ }
+ private 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;
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::render(new THtmlWriter($textWriter));
+ $stack->pop();
+ $content=$textWriter->flush();
+ $data=array($content,$this->_state,$this->_actions,time());
+ $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
+ $writer->write($content);
+ }
+ 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 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*%>|<%[%#~\/\\$=\\[](.*?)%>|)*)\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
+ {
+ $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,'$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,' $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',"");
+ $name=array_pop($stack);
+ if($name!==$type)
+ {
+ $tag=$name[0]==='@' ? ' ' : "";
+ 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,"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,' ')===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,'");
+ $name=array_pop($stack);
+ if($name!=='@'.$prop)
+ {
+ $tag=$name[0]==='@' ? '' : "";
+ 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,'