PRADO_DIR);
private static $_usings=array();
private static $_application=null;
private static $_logger=null;
protected static $classExists = array();
public static function getVersion()
{
return '3.2.0';
}
public static function initErrorHandlers()
{
set_error_handler(array('PradoBase','phpErrorHandler'));
set_exception_handler(array('PradoBase','exceptionHandler'));
}
public static function autoload($className)
{
include_once($className.self::CLASS_FILE_EXT);
if(!class_exists($className,false) && !interface_exists($className,false))
self::fatalError("Class file for '$className' cannot be found.");
}
public static function poweredByPrado($logoType=0)
{
$logoName=$logoType==1?'powered2':'powered';
if(self::$_application!==null)
{
$am=self::$_application->getAssetManager();
$url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
}
else
$url='http://www.pradosoft.com/images/'.$logoName.'.gif';
return ' ';
}
public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
{
if(error_reporting() & $errno)
throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
}
public static function exceptionHandler($exception)
{
if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
{
$errorHandler->handleError(null,$exception);
}
else
{
echo $exception;
}
exit(1);
}
public static function setApplication($application)
{
if(self::$_application!==null)
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)
{
return serialize($data);
}
public static function unserialize($str)
{
return unserialize($str);
}
public static function createComponent($type)
{
if(!isset(self::$classExists[$type]))
self::$classExists[$type] = class_exists($type, false);
if( !isset(self::$_usings[$type]) && !self::$classExists[$type]) {
self::using($type);
self::$classExists[$type] = class_exists($type, false);
}
if( ($pos = strrpos($type, '.')) !== false)
$type = substr($type,$pos+1);
if(($n=func_num_args())>1)
{
$args = func_get_args();
switch($n) {
case 2:
return new $type($args[1]);
break;
case 3:
return new $type($args[1], $args[2]);
break;
case 4:
return new $type($args[1], $args[2], $args[3]);
break;
case 5:
return new $type($args[1], $args[2], $args[3], $args[4]);
break;
default:
$s='$args[1]';
for($i=2;$i<$n;++$i)
$s.=",\$args[$i]";
eval("\$component=new $type($s);");
return $component;
break;
}
}
else
return new $type;
}
public static function using($namespace,$checkClassExistence=true)
{
if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
return;
if(($pos=strrpos($namespace,'.'))===false) {
try
{
include_once($namespace.self::CLASS_FILE_EXT);
}
catch(Exception $e)
{
if($checkClassExistence && !class_exists($namespace,false))
throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
else
throw $e;
}
}
else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
{
$className=substr($namespace,$pos+1);
if($className==='*') {
self::$_usings[$namespace]=$path;
set_include_path(get_include_path().PATH_SEPARATOR.$path);
}
else {
self::$_usings[$namespace]=$path;
if(!$checkClassExistence || !class_exists($className,false))
{
try
{
include_once($path);
}
catch(Exception $e)
{
if($checkClassExistence && !class_exists($className,false))
throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
else
throw $e;
}
}
}
}
else
throw new TInvalidDataValueException('prado_using_invalid',$namespace);
}
public static function getPathOfNamespace($namespace, $ext='')
{
if(self::CLASS_FILE_EXT === $ext || empty($ext))
{
if(isset(self::$_usings[$namespace]))
return self::$_usings[$namespace];
if(isset(self::$_aliases[$namespace]))
return self::$_aliases[$namespace];
}
$segs = explode('.',$namespace);
$alias = array_shift($segs);
if(null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias)))
return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file === '*') ? '' : DIRECTORY_SEPARATOR.$file.$ext);
return null;
}
public static function getPathOfAlias($alias)
{
return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
}
protected static function getPathAliases()
{
return self::$_aliases;
}
public static function setPathOfAlias($alias,$path)
{
if(isset(self::$_aliases[$alias]))
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',$ctl=null)
{
if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
return;
if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
{
$trace=debug_backtrace();
if(isset($trace[0]['file']) && isset($trace[0]['line']))
$msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
$level=TLogger::DEBUG;
}
else
$level=TLogger::INFO;
self::log($msg,$level,$category,$ctl);
}
public static function log($msg,$level=TLogger::INFO,$category='Uncategorized',$ctl=null)
{
if(self::$_logger===null)
self::$_logger=new TLogger;
self::$_logger->log($msg,$level,$category,$ctl);
}
public static function getLogger()
{
if(self::$_logger===null)
self::$_logger=new TLogger;
return self::$_logger;
}
public static function varDump($var,$depth=10,$highlight=false)
{
Prado::using('System.Util.TVarDumper');
return TVarDumper::dump($var,$depth,$highlight);
}
public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
{
Prado::using('System.I18N.Translation');
$app = Prado::getApplication()->getGlobalization(false);
$params = array();
foreach($parameters as $key => $value)
$params['{'.$key.'}'] = $value;
if($app===null || ($config = $app->getTranslationConfiguration())===null)
return strtr($text, $params);
if ($catalogue===null)
$catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
Translation::init($catalogue);
$appCharset = $app===null ? '' : $app->getCharset();
$defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
if(empty($charset)) $charset = $appCharset;
if(empty($charset)) $charset = $defaultCharset;
return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset);
}
}
PradoBase::using('System.TComponent');
PradoBase::using('System.Exceptions.TException');
PradoBase::using('System.Util.TLogger');
if(!class_exists('Prado',false))
{
class Prado extends PradoBase
{
}
}
spl_autoload_register(array('Prado','autoload'));
Prado::initErrorHandlers();
interface IModule
{
public function init($config);
public function getID();
public function setID($id);
}
interface IService
{
public function init($config);
public function getID();
public function setID($id);
public function getEnabled();
public function setEnabled($value);
public function run();
}
interface ITextWriter
{
public function write($str);
public function flush();
}
interface IUser
{
public function getName();
public function setName($value);
public function getIsGuest();
public function setIsGuest($value);
public function getRoles();
public function setRoles($value);
public function isInRole($role);
public function saveToString();
public function loadFromString($string);
}
interface IStatePersister
{
public function load();
public function save($state);
}
interface ICache
{
public function get($id);
public function set($id,$value,$expire=0,$dependency=null);
public function add($id,$value,$expire=0,$dependency=null);
public function delete($id);
public function flush();
}
interface ICacheDependency
{
public function getHasChanged();
}
interface IRenderable
{
public function render($writer);
}
interface IBindable
{
public function dataBind();
}
interface IStyleable
{
public function getHasStyle();
public function getStyle();
public function clearStyle();
}
interface IActiveControl
{
public function getActiveControl();
}
interface ICallbackEventHandler
{
public function raiseCallbackEvent($eventArgument);
}
interface IDataRenderer
{
public function getData();
public function setData($value);
}
class TApplicationComponent extends TComponent
{
public function getApplication()
{
return Prado::getApplication();
}
public function getService()
{
return Prado::getApplication()->getService();
}
public function getRequest()
{
return Prado::getApplication()->getRequest();
}
public function getResponse()
{
return Prado::getApplication()->getResponse();
}
public function getSession()
{
return Prado::getApplication()->getSession();
}
public function getUser()
{
return Prado::getApplication()->getUser();
}
public function publishAsset($assetPath,$className=null)
{
if($className===null)
$className=get_class($this);
$class=new ReflectionClass($className);
$fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath;
return $this->publishFilePath($fullPath);
}
public function publishFilePath($fullPath)
{
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 static function hideSecurityRelated($value, $exception=null)
{
$aRpl = array();
if($exception !== null && $exception instanceof Exception)
{
$aTrace = $exception->getTrace();
foreach($aTrace as $item)
{
if(isset($item['file']))
$aRpl[dirname($item['file']) . DIRECTORY_SEPARATOR] = '' . DIRECTORY_SEPARATOR;
}
}
$aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}';
$aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}';
$aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR;
if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]);
$aRpl = array_reverse($aRpl, true);
return str_replace(array_keys($aRpl), $aRpl, $value);
}
protected function handleExternalError($statusCode,$exception)
{
if(!($exception instanceof THttpException))
error_log($exception->__toString());
$content=$this->getErrorTemplate($statusCode,$exception);
$serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
$isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug;
$errorMessage = $exception->getMessage();
if($isDebug)
$version=$_SERVER['SERVER_SOFTWARE'].' PRADO /'.Prado::getVersion();
else
{
$version='';
$errorMessage = self::hideSecurityRelated($errorMessage, $exception);
}
$tokens=array(
'%%StatusCode%%' => "$statusCode",
'%%ErrorMessage%%' => htmlspecialchars($errorMessage),
'%%ServerAdmin%%' => $serverAdmin,
'%%Version%%' => $version,
'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
);
$CGI=substr(php_sapi_name(), 0, 3) == 'cgi'; if($isDebug)
{
if ($CGI)
header("Status: $statusCode ".$exception->getMessage(), true, TPropertyValue::ensureInteger($statusCode));
else
header("HTTP/1.0 $statusCode ".$exception->getMessage(), true, TPropertyValue::ensureInteger($statusCode));
} else {
if ($CGI)
header("Status: $statusCode", true, TPropertyValue::ensureInteger($statusCode));
else
header("HTTP/1.0 $statusCode", true, TPropertyValue::ensureInteger($statusCode));
}
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 ArrayIterator( $this->_d );
}
public function count()
{
return $this->getCount();
}
public function getCount()
{
return $this->_c;
}
public function itemAt($index)
{
if($index>=0 && $index<$this->_c)
return $this->_d[$index];
else
throw new TInvalidDataValueException('list_index_invalid',$index);
}
public function add($item)
{
$this->insertAt($this->_c,$item);
return $this->_c-1;
}
public function insertAt($index,$item)
{
if(!$this->_r)
{
if($index===$this->_c)
$this->_d[$this->_c++]=$item;
else if($index>=0 && $index<$this->_c)
{
array_splice($this->_d,$index,0,array($item));
$this->_c++;
}
else
throw new TInvalidDataValueException('list_index_invalid',$index);
}
else
throw new TInvalidOperationException('list_readonly',get_class($this));
}
public function remove($item)
{
if(!$this->_r)
{
if(($index=$this->indexOf($item))>=0)
{
$this->removeAt($index);
return $index;
}
else
throw new TInvalidDataValueException('list_item_inexistent');
}
else
throw new TInvalidOperationException('list_readonly',get_class($this));
}
public function removeAt($index)
{
if(!$this->_r)
{
if($index>=0 && $index<$this->_c)
{
$this->_c--;
if($index===$this->_c)
return array_pop($this->_d);
else
{
$item=$this->_d[$index];
array_splice($this->_d,$index,1);
return $item;
}
}
else
throw new TInvalidDataValueException('list_index_invalid',$index);
}
else
throw new TInvalidOperationException('list_readonly',get_class($this));
}
public function clear()
{
for($i=$this->_c-1;$i>=0;--$i)
$this->removeAt($i);
}
public function contains($item)
{
return $this->indexOf($item)>=0;
}
public function indexOf($item)
{
if(($index=array_search($item,$this->_d,true))===false)
return -1;
else
return $index;
}
public function insertBefore($baseitem, $item)
{
if(!$this->_r)
{
if(($index = $this->indexOf($baseitem)) == -1)
throw new TInvalidDataValueException('list_item_inexistent');
$this->insertAt($index, $item);
return $index;
}
else
throw new TInvalidOperationException('list_readonly',get_class($this));
}
public function insertAfter($baseitem, $item)
{
if(!$this->_r)
{
if(($index = $this->indexOf($baseitem)) == -1)
throw new TInvalidDataValueException('list_item_inexistent');
$this->insertAt($index + 1, $item);
return $index + 1;
}
else
throw new TInvalidOperationException('list_readonly',get_class($this));
}
public function toArray()
{
return $this->_d;
}
public function copyFrom($data)
{
if(is_array($data) || ($data instanceof Traversable))
{
if($this->_c>0)
$this->clear();
foreach($data as $item)
$this->add($item);
}
else if($data!==null)
throw new TInvalidDataTypeException('list_data_not_iterable');
}
public function mergeWith($data)
{
if(is_array($data) || ($data instanceof Traversable))
{
foreach($data as $item)
$this->add($item);
}
else if($data!==null)
throw new TInvalidDataTypeException('list_data_not_iterable');
}
public function offsetExists($offset)
{
return ($offset>=0 && $offset<$this->_c);
}
public function offsetGet($offset)
{
return $this->itemAt($offset);
}
public function offsetSet($offset,$item)
{
if($offset===null || $offset===$this->_c)
$this->insertAt($this->_c,$item);
else
{
$this->removeAt($offset);
$this->insertAt($offset,$item);
}
}
public function offsetUnset($offset)
{
$this->removeAt($offset);
}
}
class TListIterator implements Iterator
{
private $_d;
private $_i;
private $_c;
public function __construct(&$data)
{
$this->_d=&$data;
$this->_i=0;
$this->_c=count($this->_d);
}
public function rewind()
{
$this->_i=0;
}
public function key()
{
return $this->_i;
}
public function current()
{
return $this->_d[$this->_i];
}
public function next()
{
$this->_i++;
}
public function valid()
{
return $this->_i<$this->_c;
}
}
abstract class TCache extends TModule implements ICache, ArrayAccess
{
private $_prefix=null;
private $_primary=true;
public function init($config)
{
if($this->_prefix===null)
$this->_prefix=$this->getApplication()->getUniqueID();
if($this->_primary)
{
if($this->getApplication()->getCache()===null)
$this->getApplication()->setCache($this);
else
throw new TConfigurationException('cache_primary_duplicated',get_class($this));
}
}
public function getPrimaryCache()
{
return $this->_primary;
}
public function setPrimaryCache($value)
{
$this->_primary=TPropertyValue::ensureBoolean($value);
}
public function getKeyPrefix()
{
return $this->_prefix;
}
public function setKeyPrefix($value)
{
$this->_prefix=$value;
}
protected function generateUniqueKey($key)
{
return md5($this->_prefix.$key);
}
public function get($id)
{
if(($data=$this->getValue($this->generateUniqueKey($id)))!==false)
{
if(!is_array($data))
return false;
if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
return $data[0];
}
return false;
}
public function set($id,$value,$expire=0,$dependency=null)
{
if(empty($value) && $expire === 0)
$this->delete($id);
else
{
$data=array($value,$dependency);
return $this->setValue($this->generateUniqueKey($id),$data,$expire);
}
}
public function add($id,$value,$expire=0,$dependency=null)
{
if(empty($value) && $expire === 0)
return false;
$data=array($value,$dependency);
return $this->addValue($this->generateUniqueKey($id),$data,$expire);
}
public function delete($id)
{
return $this->deleteValue($this->generateUniqueKey($id));
}
public function flush()
{
throw new TNotSupportedException('cache_flush_unsupported');
}
abstract protected function getValue($key);
abstract protected function setValue($key,$value,$expire);
abstract protected function addValue($key,$value,$expire);
abstract protected function deleteValue($key);
public function offsetExists($id)
{
return $this->get($id) !== false;
}
public function offsetGet($id)
{
return $this->get($id);
}
public function offsetSet($id, $value)
{
$this->set($id, $value);
}
public function offsetUnset($id)
{
$this->delete($id);
}
}
abstract class TCacheDependency extends TComponent implements ICacheDependency
{
}
class TFileCacheDependency extends TCacheDependency
{
private $_fileName;
private $_timestamp;
public function __construct($fileName)
{
$this->setFileName($fileName);
}
public function getFileName()
{
return $this->_fileName;
}
public function setFileName($value)
{
$this->_fileName=$value;
$this->_timestamp=@filemtime($value);
}
public function getTimestamp()
{
return $this->_timestamp;
}
public function getHasChanged()
{
return @filemtime($this->_fileName)!==$this->_timestamp;
}
}
class TDirectoryCacheDependency extends TCacheDependency
{
private $_recursiveCheck=true;
private $_recursiveLevel=-1;
private $_timestamps;
private $_directory;
public function __construct($directory)
{
$this->setDirectory($directory);
}
public function getDirectory()
{
return $this->_directory;
}
public function setDirectory($directory)
{
if(($path=realpath($directory))===false || !is_dir($path))
throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
$this->_directory=$path;
$this->_timestamps=$this->generateTimestamps($path);
}
public function getRecursiveCheck()
{
return $this->_recursiveCheck;
}
public function setRecursiveCheck($value)
{
$this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
}
public function getRecursiveLevel()
{
return $this->_recursiveLevel;
}
public function setRecursiveLevel($value)
{
$this->_recursiveLevel=TPropertyValue::ensureInteger($value);
}
public function getHasChanged()
{
return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
}
protected function validateFile($fileName)
{
return true;
}
protected function validateDirectory($directory)
{
return true;
}
protected function generateTimestamps($directory,$level=0)
{
if(($dir=opendir($directory))===false)
throw new TIOException('directorycachedependency_directory_invalid',$directory);
$timestamps=array();
while(($file=readdir($dir))!==false)
{
$path=$directory.DIRECTORY_SEPARATOR.$file;
if($file==='.' || $file==='..')
continue;
else if(is_dir($path))
{
if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
$timestamps=array_merge($this->generateTimestamps($path,$level+1));
}
else if($this->validateFile($path))
$timestamps[$path]=filemtime($path);
}
closedir($dir);
return $timestamps;
}
}
class TGlobalStateCacheDependency extends TCacheDependency
{
private $_stateName;
private $_stateValue;
public function __construct($name)
{
$this->setStateName($name);
}
public function getStateName()
{
return $this->_stateName;
}
public function setStateName($value)
{
$this->_stateName=$value;
$this->_stateValue=Prado::getApplication()->getGlobalState($value);
}
public function getHasChanged()
{
return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
}
}
class TChainedCacheDependency extends TCacheDependency
{
private $_dependencies=null;
public function getDependencies()
{
if($this->_dependencies===null)
$this->_dependencies=new TCacheDependencyList;
return $this->_dependencies;
}
public function getHasChanged()
{
if($this->_dependencies!==null)
{
foreach($this->_dependencies as $dependency)
if($dependency->getHasChanged())
return true;
}
return false;
}
}
class TApplicationStateCacheDependency extends TCacheDependency
{
public function getHasChanged()
{
return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
}
}
class TCacheDependencyList extends TList
{
public function insertAt($index,$item)
{
if($item instanceof ICacheDependency)
parent::insertAt($index,$item);
else
throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
}
}
class TTextWriter extends TComponent implements ITextWriter
{
private $_str='';
public function flush()
{
$str=$this->_str;
$this->_str='';
return $str;
}
public function write($str)
{
$this->_str.=$str;
}
public function writeLine($str='')
{
$this->write($str."\n");
}
}
class TPriorityList extends TList
{
private $_d=array();
private $_o=false;
private $_fd=null;
private $_c=0;
private $_dp=10;
private $_p=8;
public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
{
parent::__construct();
if($data!==null)
$this->copyFrom($data);
$this->setReadOnly($readOnly);
$this->setPrecision($precision);
$this->setDefaultPriority($defaultPriority);
}
public function count()
{
return $this->getCount();
}
public function getCount()
{
return $this->_c;
}
public function getPriorityCount($priority=null)
{
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
if(!isset($this->_d[$priority]) || !is_array($this->_d[$priority]))
return false;
return count($this->_d[$priority]);
}
public function getDefaultPriority()
{
return $this->_dp;
}
protected function setDefaultPriority($value)
{
$this->_dp=(string)round(TPropertyValue::ensureFloat($value),$this->_p);
}
public function getPrecision()
{
return $this->_p;
}
protected function setPrecision($value)
{
$this->_p=TPropertyValue::ensureInteger($value);
}
public function getIterator()
{
return new ArrayIterator($this->flattenPriorities());
}
public function getPriorities()
{
$this->sortPriorities();
return array_keys($this->_d);
}
protected function sortPriorities() {
if(!$this->_o) {
ksort($this->_d,SORT_NUMERIC);
$this->_o=true;
}
}
protected function flattenPriorities() {
if(is_array($this->_fd))
return $this->_fd;
$this->sortPriorities();
$this->_fd=array();
foreach($this->_d as $priority => $itemsatpriority)
$this->_fd=array_merge($this->_fd,$itemsatpriority);
return $this->_fd;
}
public function itemAt($index)
{
if($index>=0&&$index<$this->getCount()) {
$arr=$this->flattenPriorities();
return $arr[$index];
} else
throw new TInvalidDataValueException('list_index_invalid',$index);
}
public function itemsAtPriority($priority=null)
{
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
return isset($this->_d[$priority])?$this->_d[$priority]:null;
}
public function itemAtIndexInPriority($index,$priority=null)
{
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
return !isset($this->_d[$priority])?false:(
isset($this->_d[$priority][$index])?$this->_d[$priority][$index]:false
);
}
public function add($item,$priority=null)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
return $this->insertAtIndexInPriority($item,false,$priority,true);
}
public function insertAt($index,$item)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
if(($priority=$this->priorityAt($index,true))!==false)
$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
else
throw new TInvalidDataValueException('list_index_invalid',$index);
}
public function insertAtIndexInPriority($item,$index=false,$priority=null,$preserveCache=false)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
if($preserveCache) {
$this->sortPriorities();
$cc=0;
foreach($this->_d as $prioritykey=>$items)
if($prioritykey>=$priority)
break;
else
$cc+=count($items);
if($index===false&&isset($this->_d[$priority])) {
$c=count($this->_d[$priority]);
$c+=$cc;
$this->_d[$priority][]=$item;
} else if(isset($this->_d[$priority])) {
$c=$index+$cc;
array_splice($this->_d[$priority],$index,0,array($item));
} else {
$c = $cc;
$this->_o = false;
$this->_d[$priority]=array($item);
}
if($this->_fd&&is_array($this->_fd)) array_splice($this->_fd,$c,0,array($item));
} else {
$c=null;
if($index===false&&isset($this->_d[$priority])) {
$cc=count($this->_d[$priority]);
$this->_d[$priority][]=$item;
} else if(isset($this->_d[$priority])) {
$cc=$index;
array_splice($this->_d[$priority],$index,0,array($item));
} else {
$cc=0;
$this->_o=false;
$this->_d[$priority]=array($item);
}
if($this->_fd&&is_array($this->_fd)&&count($this->_d)==1)
array_splice($this->_fd,$cc,0,array($item));
else
$this->_fd=null;
}
$this->_c++;
return $c;
}
public function remove($item,$priority=false)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
if(($p=$this->priorityOf($item,true))!==false)
{
if($priority!==false) {
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
if($p[0]!=$priority)
throw new TInvalidDataValueException('list_item_inexistent');
}
$this->removeAtIndexInPriority($p[1],$p[0]);
return $p[2];
}
else
throw new TInvalidDataValueException('list_item_inexistent');
}
public function removeAt($index)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
if(($priority=$this->priorityAt($index, true))!==false)
return $this->removeAtIndexInPriority($priority[1],$priority[0]);
throw new TInvalidDataValueException('list_index_invalid',$index);
}
public function removeAtIndexInPriority($index, $priority=null)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
if(!isset($this->_d[$priority])||$index<0||$index>=count($this->_d[$priority]))
throw new TInvalidDataValueException('list_item_inexistent');
$value=array_splice($this->_d[$priority],$index,1);
$value=$value[0];
if(!count($this->_d[$priority]))
unset($this->_d[$priority]);
$this->_c--;
$this->_fd=null;
return $value;
}
public function clear()
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
$d=array_reverse($this->_d,true);
foreach($this->_d as $priority=>$items) {
for($index=count($items)-1;$index>=0;$index--)
$this->removeAtIndexInPriority($index,$priority);
unset($this->_d[$priority]);
}
}
public function contains($item)
{
return $this->indexOf($item)>=0;
}
public function indexOf($item)
{
if(($index=array_search($item,$this->flattenPriorities(),true))===false)
return -1;
else
return $index;
}
public function priorityOf($item,$withindex = false)
{
$this->sortPriorities();
$absindex = 0;
foreach($this->_d as $priority=>$items) {
if(($index=array_search($item,$items,true))!==false) {
$absindex+=$index;
return $withindex?array($priority,$index,$absindex,
'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
} else
$absindex+=count($items);
}
return false;
}
public function priorityAt($index,$withindex = false)
{
if($index<0||$index>=$this->getCount())
throw new TInvalidDataValueException('list_index_invalid',$index);
$absindex=$index;
$this->sortPriorities();
foreach($this->_d as $priority=>$items) {
if($index>=($c=count($items)))
$index-=$c;
else
return $withindex?array($priority,$index,$absindex,
'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
}
return false;
}
public function insertBefore($indexitem, $item)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
if(($priority=$this->priorityOf($indexitem,true))===false)
throw new TInvalidDataValueException('list_item_inexistent');
$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
return $priority[2];
}
public function insertAfter($indexitem, $item)
{
if($this->getReadOnly())
throw new TInvalidOperationException('list_readonly',get_class($this));
if(($priority=$this->priorityOf($indexitem,true))===false)
throw new TInvalidDataValueException('list_item_inexistent');
$this->insertAtIndexInPriority($item,$priority[1]+1,$priority[0]);
return $priority[2]+1;
}
public function toArray()
{
return $this->flattenPriorities();
}
public function toPriorityArray()
{
$this->sortPriorities();
return $this->_d;
}
public function toArrayBelowPriority($priority,$inclusive=false)
{
$this->sortPriorities();
$items=array();
foreach($this->_d as $itemspriority=>$itemsatpriority)
{
if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
break;
$items=array_merge($items,$itemsatpriority);
}
return $items;
}
public function toArrayAbovePriority($priority,$inclusive=true)
{
$this->sortPriorities();
$items=array();
foreach($this->_d as $itemspriority=>$itemsatpriority)
{
if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
continue;
$items=array_merge($items,$itemsatpriority);
}
return $items;
}
public function copyFrom($data)
{
if($data instanceof TPriorityList)
{
if($this->getCount()>0)
$this->clear();
foreach($data->getPriorities() as $priority)
{
foreach($data->itemsAtPriority($priority) as $index=>$item)
$this->insertAtIndexInPriority($item,$index,$priority);
}
} else if(is_array($data)||$data instanceof Traversable) {
if($this->getCount()>0)
$this->clear();
foreach($data as $key=>$item)
$this->add($item);
} else if($data!==null)
throw new TInvalidDataTypeException('map_data_not_iterable');
}
public function mergeWith($data)
{
if($data instanceof TPriorityList)
{
foreach($data->getPriorities() as $priority)
{
foreach($data->itemsAtPriority($priority) as $index=>$item)
$this->insertAtIndexInPriority($item,false,$priority);
}
}
else if(is_array($data)||$data instanceof Traversable)
{
foreach($data as $priority=>$item)
$this->add($item);
}
else if($data!==null)
throw new TInvalidDataTypeException('map_data_not_iterable');
}
public function offsetExists($offset)
{
return ($offset>=0&&$offset<$this->getCount());
}
public function offsetGet($offset)
{
return $this->itemAt($offset);
}
public function offsetSet($offset,$item)
{
if($offset===null)
return $this->add($item);
if($offset===$this->getCount()) {
$priority=$this->priorityAt($offset-1,true);
$priority[1]++;
} else {
$priority=$this->priorityAt($offset,true);
$this->removeAtIndexInPriority($priority[1],$priority[0]);
}
$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
}
public function offsetUnset($offset)
{
$this->removeAt($offset);
}
}
class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable
{
private $_d=array();
private $_r=false;
public function __construct($data=null,$readOnly=false)
{
if($data!==null)
$this->copyFrom($data);
$this->setReadOnly($readOnly);
}
public function getReadOnly()
{
return $this->_r;
}
protected function setReadOnly($value)
{
$this->_r=TPropertyValue::ensureBoolean($value);
}
public function getIterator()
{
return new ArrayIterator( $this->_d );
}
public function count()
{
return $this->getCount();
}
public function getCount()
{
return count($this->_d);
}
public function getKeys()
{
return array_keys($this->_d);
}
public function itemAt($key)
{
return isset($this->_d[$key]) ? $this->_d[$key] : null;
}
public function add($key,$value)
{
if(!$this->_r)
$this->_d[$key]=$value;
else
throw new TInvalidOperationException('map_readonly',get_class($this));
}
public function remove($key)
{
if(!$this->_r)
{
if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
{
$value=$this->_d[$key];
unset($this->_d[$key]);
return $value;
}
else
return null;
}
else
throw new TInvalidOperationException('map_readonly',get_class($this));
}
public function clear()
{
foreach(array_keys($this->_d) as $key)
$this->remove($key);
}
public function contains($key)
{
return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
}
public function toArray()
{
return $this->_d;
}
public function copyFrom($data)
{
if(is_array($data) || $data instanceof Traversable)
{
if($this->getCount()>0)
$this->clear();
foreach($data as $key=>$value)
$this->add($key,$value);
}
else if($data!==null)
throw new TInvalidDataTypeException('map_data_not_iterable');
}
public function mergeWith($data)
{
if(is_array($data) || $data instanceof Traversable)
{
foreach($data as $key=>$value)
$this->add($key,$value);
}
else if($data!==null)
throw new TInvalidDataTypeException('map_data_not_iterable');
}
public function offsetExists($offset)
{
return $this->contains($offset);
}
public function offsetGet($offset)
{
return $this->itemAt($offset);
}
public function offsetSet($offset,$item)
{
$this->add($offset,$item);
}
public function offsetUnset($offset)
{
$this->remove($offset);
}
}
class TMapIterator implements Iterator
{
private $_d;
private $_keys;
private $_key;
public function __construct(&$data)
{
$this->_d=&$data;
$this->_keys=array_keys($data);
}
public function rewind()
{
$this->_key=reset($this->_keys);
}
public function key()
{
return $this->_key;
}
public function current()
{
return $this->_d[$this->_key];
}
public function next()
{
$this->_key=next($this->_keys);
}
public function valid()
{
return $this->_key!==false;
}
}
class TPriorityMap extends TMap
{
private $_d=array();
private $_r=false;
private $_o=false;
private $_fd=null;
private $_c=0;
private $_dp=10;
private $_p=8;
public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
{
if($data!==null)
$this->copyFrom($data);
$this->setReadOnly($readOnly);
$this->setPrecision($precision);
$this->setDefaultPriority($defaultPriority);
}
public function getReadOnly()
{
return $this->_r;
}
protected function setReadOnly($value)
{
$this->_r=TPropertyValue::ensureBoolean($value);
}
public function getDefaultPriority()
{
return $this->_dp;
}
protected function setDefaultPriority($value)
{
$this->_dp = (string)round(TPropertyValue::ensureFloat($value), $this->_p);
}
public function getPrecision()
{
return $this->_p;
}
protected function setPrecision($value)
{
$this->_p=TPropertyValue::ensureInteger($value);
}
public function getIterator()
{
return new ArrayIterator($this->flattenPriorities());
}
protected function sortPriorities() {
if(!$this->_o) {
ksort($this->_d, SORT_NUMERIC);
$this->_o=true;
}
}
protected function flattenPriorities() {
if(is_array($this->_fd))
return $this->_fd;
$this->sortPriorities();
$this->_fd = array();
foreach($this->_d as $priority => $itemsatpriority)
$this->_fd = array_merge($this->_fd, $itemsatpriority);
return $this->_fd;
}
public function count()
{
return $this->getCount();
}
public function getCount()
{
return $this->_c;
}
public function getPriorityCount($priority=null)
{
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
if(!isset($this->_d[$priority])||!is_array($this->_d[$priority]))
return false;
return count($this->_d[$priority]);
}
public function getPriorities()
{
$this->sortPriorities();
return array_keys($this->_d);
}
public function getKeys()
{
return array_keys($this->flattenPriorities());
}
public function itemAt($key,$priority=false)
{
if($priority===false){
$map=$this->flattenPriorities();
return isset($map[$key])?$map[$key]:null;
} else {
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
return (isset($this->_d[$priority])&&isset($this->_d[$priority][$key]))?$this->_d[$priority][$key]:null;
}
}
public function setPriorityAt($key,$priority=null)
{
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
$oldpriority=$this->priorityAt($key);
if($oldpriority!==false&&$oldpriority!=$priority) {
$value=$this->remove($key,$oldpriority);
$this->add($key,$value,$priority);
}
return $oldpriority;
}
public function itemsAtPriority($priority=null)
{
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
return isset($this->_d[$priority])?$this->_d[$priority]:null;
}
public function priorityOf($item)
{
$this->sortPriorities();
foreach($this->_d as $priority=>$items)
if(($index=array_search($item,$items,true))!==false)
return $priority;
return false;
}
public function priorityAt($key)
{
$this->sortPriorities();
foreach($this->_d as $priority=>$items)
if(array_key_exists($key,$items))
return $priority;
return false;
}
public function add($key,$value,$priority=null)
{
if($priority===null)
$priority=$this->getDefaultPriority();
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
if(!$this->_r)
{
foreach($this->_d as $innerpriority=>$items)
if(array_key_exists($key,$items))
{
unset($this->_d[$innerpriority][$key]);
$this->_c--;
if(count($this->_d[$innerpriority])===0)
unset($this->_d[$innerpriority]);
}
if(!isset($this->_d[$priority])) {
$this->_d[$priority]=array($key=>$value);
$this->_o=false;
}
else
$this->_d[$priority][$key]=$value;
$this->_c++;
$this->_fd=null;
}
else
throw new TInvalidOperationException('map_readonly',get_class($this));
return $priority;
}
public function remove($key,$priority=false)
{
if(!$this->_r)
{
if($priority===null)
$priority=$this->getDefaultPriority();
if($priority===false)
{
$this->sortPriorities();
foreach($this->_d as $priority=>$items)
if(array_key_exists($key,$items))
{
$value=$this->_d[$priority][$key];
unset($this->_d[$priority][$key]);
$this->_c--;
if(count($this->_d[$priority])===0)
{
unset($this->_d[$priority]);
$this->_o=false;
}
$this->_fd=null;
return $value;
}
return null;
}
else
{
$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
if(isset($this->_d[$priority])&&(isset($this->_d[$priority][$key])||array_key_exists($key,$this->_d[$priority])))
{
$value=$this->_d[$priority][$key];
unset($this->_d[$priority][$key]);
$this->_c--;
if(count($this->_d[$priority])===0) {
unset($this->_d[$priority]);
$this->_o=false;
}
$this->_fd=null;
return $value;
}
else
return null;
}
}
else
throw new TInvalidOperationException('map_readonly',get_class($this));
}
public function clear()
{
foreach($this->_d as $priority=>$items)
foreach(array_keys($items) as $key)
$this->remove($key);
}
public function contains($key)
{
$map=$this->flattenPriorities();
return isset($map[$key])||array_key_exists($key,$map);
}
public function toArray()
{
return $this->flattenPriorities();
}
public function toArrayBelowPriority($priority,$inclusive=false)
{
$this->sortPriorities();
$items=array();
foreach($this->_d as $itemspriority=>$itemsatpriority)
{
if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
break;
$items=array_merge($items,$itemsatpriority);
}
return $items;
}
public function toArrayAbovePriority($priority,$inclusive=true)
{
$this->sortPriorities();
$items=array();
foreach($this->_d as $itemspriority=>$itemsatpriority)
{
if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
continue;
$items=array_merge($items,$itemsatpriority);
}
return $items;
}
public function copyFrom($data)
{
if($data instanceof TPriorityMap)
{
if($this->getCount()>0)
$this->clear();
foreach($data->getPriorities() as $priority) {
foreach($data->itemsAtPriority($priority) as $key => $value) {
$this->add($key,$value,$priority);
}
}
}
else if(is_array($data)||$data instanceof Traversable)
{
if($this->getCount()>0)
$this->clear();
foreach($data as $key=>$value)
$this->add($key,$value);
}
else if($data!==null)
throw new TInvalidDataTypeException('map_data_not_iterable');
}
public function mergeWith($data)
{
if($data instanceof TPriorityMap)
{
foreach($data->getPriorities() as $priority)
{
foreach($data->itemsAtPriority($priority) as $key => $value)
$this->add($key,$value,$priority);
}
}
else if(is_array($data)||$data instanceof Traversable)
{
foreach($data as $key=>$value)
$this->add($key,$value);
}
else if($data!==null)
throw new TInvalidDataTypeException('map_data_not_iterable');
}
public function offsetExists($offset)
{
return $this->contains($offset);
}
public function offsetGet($offset)
{
return $this->itemAt($offset);
}
public function offsetSet($offset,$item)
{
$this->add($offset,$item);
}
public function offsetUnset($offset)
{
$this->remove($offset);
}
}
class TStack extends TComponent implements IteratorAggregate,Countable
{
private $_d=array();
private $_c=0;
public function __construct($data=null)
{
if($data!==null)
$this->copyFrom($data);
}
public function toArray()
{
return $this->_d;
}
public function copyFrom($data)
{
if(is_array($data) || ($data instanceof Traversable))
{
$this->clear();
foreach($data as $item)
{
$this->_d[]=$item;
++$this->_c;
}
}
else if($data!==null)
throw new TInvalidDataTypeException('stack_data_not_iterable');
}
public function clear()
{
$this->_c=0;
$this->_d=array();
}
public function contains($item)
{
return array_search($item,$this->_d,true)!==false;
}
public function peek()
{
if($this->_c===0)
throw new TInvalidOperationException('stack_empty');
else
return $this->_d[$this->_c-1];
}
public function pop()
{
if($this->_c===0)
throw new TInvalidOperationException('stack_empty');
else
{
--$this->_c;
return array_pop($this->_d);
}
}
public function push($item)
{
++$this->_c;
$this->_d[] = $item;
}
public function getIterator()
{
return new ArrayIterator( $this->_d );
}
public function getCount()
{
return $this->_c;
}
public function count()
{
return $this->getCount();
}
}
class TStackIterator implements Iterator
{
private $_d;
private $_i;
private $_c;
public function __construct(&$data)
{
$this->_d=&$data;
$this->_i=0;
$this->_c=count($this->_d);
}
public function rewind()
{
$this->_i=0;
}
public function key()
{
return $this->_i;
}
public function current()
{
return $this->_d[$this->_i];
}
public function next()
{
$this->_i++;
}
public function valid()
{
return $this->_i<$this->_c;
}
}
class TXmlElement extends TComponent
{
private $_parent=null;
private $_tagName='unknown';
private $_value='';
private $_elements=null;
private $_attributes=null;
public function __construct($tagName)
{
$this->setTagName($tagName);
}
public function getParent()
{
return $this->_parent;
}
public function setParent($parent)
{
$this->_parent=$parent;
}
public function getTagName()
{
return $this->_tagName;
}
public function setTagName($tagName)
{
$this->_tagName=$tagName;
}
public function getValue()
{
return $this->_value;
}
public function setValue($value)
{
$this->_value=TPropertyValue::ensureString($value);
}
public function getHasElement()
{
return $this->_elements!==null && $this->_elements->getCount()>0;
}
public function getHasAttribute()
{
return $this->_attributes!==null && $this->_attributes->getCount()>0;
}
public function getAttribute($name)
{
if($this->_attributes!==null)
return $this->_attributes->itemAt($name);
else
return null;
}
public function setAttribute($name,$value)
{
$this->getAttributes()->add($name,TPropertyValue::ensureString($value));
}
public function getElements()
{
if(!$this->_elements)
$this->_elements=new TXmlElementList($this);
return $this->_elements;
}
public function getAttributes()
{
if(!$this->_attributes)
$this->_attributes=new TMap;
return $this->_attributes;
}
public function getElementByTagName($tagName)
{
if($this->_elements)
{
foreach($this->_elements as $element)
if($element->_tagName===$tagName)
return $element;
}
return null;
}
public function getElementsByTagName($tagName)
{
$list=new TList;
if($this->_elements)
{
foreach($this->_elements as $element)
if($element->_tagName===$tagName)
$list->add($element);
}
return $list;
}
public function toString($indent=0)
{
$attr='';
if($this->_attributes!==null)
{
foreach($this->_attributes as $name=>$value)
{
$value=$this->xmlEncode($value);
$attr.=" $name=\"$value\"";
}
}
$prefix=str_repeat(' ',$indent*4);
if($this->getHasElement())
{
$str=$prefix."<{$this->_tagName}$attr>\n";
foreach($this->getElements() as $element)
$str.=$element->toString($indent+1)."\n";
$str.=$prefix."{$this->_tagName}>";
return $str;
}
else if(($value=$this->getValue())!=='')
{
$value=$this->xmlEncode($value);
return $prefix."<{$this->_tagName}$attr>$value{$this->_tagName}>";
}
else
return $prefix."<{$this->_tagName}$attr />";
}
public function __toString()
{
return $this->toString();
}
private function xmlEncode($str)
{
return strtr($str,array(
'>'=>'>',
'<'=>'<',
'&'=>'&',
'"'=>'"',
"\r"=>'
',
"\t"=>' ',
"\n"=>'
'));
}
}
class TXmlDocument extends TXmlElement
{
private $_version;
private $_encoding;
public function __construct($version='1.0',$encoding='')
{
parent::__construct('');
$this->setVersion($version);
$this->setEncoding($encoding);
}
public function getVersion()
{
return $this->_version;
}
public function setVersion($version)
{
$this->_version=$version;
}
public function getEncoding()
{
return $this->_encoding;
}
public function setEncoding($encoding)
{
$this->_encoding=$encoding;
}
public function loadFromFile($file)
{
if(($str=@file_get_contents($file))!==false)
return $this->loadFromString($str);
else
throw new TIOException('xmldocument_file_read_failed',$file);
}
public function loadFromString($string)
{
$doc=new DOMDocument();
if($doc->loadXML($string)===false)
return false;
$this->setEncoding($doc->encoding);
$this->setVersion($doc->version);
$element=$doc->documentElement;
$this->setTagName($element->tagName);
$this->setValue($element->nodeValue);
$elements=$this->getElements();
$attributes=$this->getAttributes();
$elements->clear();
$attributes->clear();
static $bSimpleXml;
if($bSimpleXml === null)
$bSimpleXml = (boolean)function_exists('simplexml_load_string');
if($bSimpleXml)
{
$simpleDoc = simplexml_load_string($string);
$docNamespaces = $simpleDoc->getDocNamespaces(false);
$simpleDoc = null;
foreach($docNamespaces as $prefix => $uri)
{
if($prefix === '')
$attributes->add('xmlns', $uri);
else
$attributes->add('xmlns:'.$prefix, $uri);
}
}
foreach($element->attributes as $name=>$attr)
$attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value);
foreach($element->childNodes as $child)
{
if($child instanceof DOMElement)
$elements->add($this->buildElement($child));
}
return true;
}
public function saveToFile($file)
{
if(($fw=fopen($file,'w'))!==false)
{
fwrite($fw,$this->saveToString());
fclose($fw);
}
else
throw new TIOException('xmldocument_file_write_failed',$file);
}
public function saveToString()
{
$version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
$encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
return "\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 $_hashAlgorithm = 'sha1';
private $_cryptAlgorithm = 'rijndael-256';
private $_mbstring;
public function init($config)
{
$this->_mbstring=extension_loaded('mbstring');
$this->getApplication()->setSecurityManager($this);
}
protected function generateRandomKey()
{
return sprintf('%08x%08x%08x%08x',mt_rand(),mt_rand(),mt_rand(),mt_rand());
}
public function getValidationKey()
{
if(null === $this->_validationKey) {
if(null === ($this->_validationKey = $this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))) {
$this->_validationKey = $this->generateRandomKey();
$this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY, $this->_validationKey, null, true);
}
}
return $this->_validationKey;
}
public function setValidationKey($value)
{
if('' === $value)
throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
$this->_validationKey = $value;
}
public function getEncryptionKey()
{
if(null === $this->_encryptionKey) {
if(null === ($this->_encryptionKey = $this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))) {
$this->_encryptionKey = $this->generateRandomKey();
$this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY, $this->_encryptionKey, null, true);
}
}
return $this->_encryptionKey;
}
public function setEncryptionKey($value)
{
if('' === $value)
throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
$this->_encryptionKey = $value;
}
public function getValidation()
{
return $this->_hashAlgorithm;
}
public function getHashAlgorithm()
{
return $this->_hashAlgorithm;
}
public function setValidation($value)
{
$this->_hashAlgorithm = TPropertyValue::ensureEnum($value, 'TSecurityManagerValidationMode');
}
public function setHashAlgorithm($value)
{
$this->_hashAlgorithm = TPropertyValue::ensureString($value);
}
public function getEncryption()
{
if(is_string($this->_cryptAlgorithm))
return $this->_cryptAlgorithm;
return "3DES";
}
public function setEncryption($value)
{
$this->_cryptAlgorithm = $value;
}
public function getCryptAlgorithm()
{
return $this->_cryptAlgorithm;
}
public function setCryptAlgorithm($value)
{
$this->_cryptAlgorithm = $value;
}
public function encrypt($data)
{
$module=$this->openCryptModule();
$key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
srand();
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
mcrypt_generic_init($module, $key, $iv);
$encrypted = $iv.mcrypt_generic($module, $data);
mcrypt_generic_deinit($module);
mcrypt_module_close($module);
return $encrypted;
}
public function decrypt($data)
{
$module=$this->openCryptModule();
$key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
$ivSize = mcrypt_enc_get_iv_size($module);
$iv = $this->substr($data, 0, $ivSize);
mcrypt_generic_init($module, $key, $iv);
$decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data)));
mcrypt_generic_deinit($module);
mcrypt_module_close($module);
return $decrypted;
}
protected function openCryptModule()
{
if(extension_loaded('mcrypt'))
{
if(is_array($this->_cryptAlgorithm))
$module=@call_user_func_array('mcrypt_module_open',$this->_cryptAlgorithm);
else
$module=@mcrypt_module_open($this->_cryptAlgorithm,'', MCRYPT_MODE_CBC,'');
if($module===false)
throw new TNotSupportedException('securitymanager_mcryptextension_initfailed');
return $module;
}
else
throw new TNotSupportedException('securitymanager_mcryptextension_required');
}
public function hashData($data)
{
$hmac = $this->computeHMAC($data);
return $hmac.$data;
}
public function validateData($data)
{
$len=$this->strlen($this->computeHMAC('test'));
if($this->strlen($data) < $len)
return false;
$hmac = $this->substr($data, 0, $len);
$data2=$this->substr($data, $len, $this->strlen($data));
return $hmac === $this->computeHMAC($data2) ? $data2 : false;
}
protected function computeHMAC($data)
{
$key = $this->getValidationKey();
if(function_exists('hash_hmac'))
return hash_hmac($this->_hashAlgorithm, $data, $key);
if(!strcasecmp($this->_hashAlgorithm,'sha1'))
{
$pack = 'H40';
$func = 'sha1';
} else {
$pack = 'H32';
$func = 'md5';
}
$key = str_pad($func($key), 64, chr(0));
return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
}
private function strlen($string)
{
return $this->_mbstring ? mb_strlen($string,'8bit') : strlen($string);
}
private function substr($string,$start,$length)
{
return $this->_mbstring ? mb_substr($string,$start,$length,'8bit') : substr($string,$start,$length);
}
}
class TSecurityManagerValidationMode extends TEnumerable
{
const MD5 = 'MD5';
const SHA1 = 'SHA1';
}
class THttpUtility
{
private static $_encodeTable=array('<'=>'<','>'=>'>','"'=>'"');
private static $_decodeTable=array('<'=>'<','>'=>'>','"'=>'"');
private static $_stripTable=array('<'=>'','>'=>'','"'=>'');
public static function htmlEncode($s)
{
return strtr($s,self::$_encodeTable);
}
public static function htmlDecode($s)
{
return strtr($s,self::$_decodeTable);
}
public static function htmlStrip($s)
{
return strtr($s,self::$_stripTable);
}
}
class TJavaScript
{
public static function renderScriptFiles($files)
{
$str='';
foreach($files as $file)
$str.= self::renderScriptFile($file);
return $str;
}
public static function renderScriptFile($file)
{
return '\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)
{
return self::jsonEncode($js,JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG);
}
public static function quoteJsLiteral($js)
{
if($js instanceof TJavaScriptLiteral)
return $js;
else
return new TJavaScriptLiteral($js);
}
public static function quoteFunction($js)
{
return self::quoteJsLiteral($js);
}
public static function isJsLiteral($js)
{
return ($js instanceof TJavaScriptLiteral);
}
public static function isFunction($js)
{
return self::isJsLiteral($js);
}
public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
{
if(is_string($value))
return self::quoteString($value);
else if(is_bool($value))
return $value?'true':'false';
else if(is_array($value))
{
$results='';
if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
{
foreach($value as $k=>$v)
{
if($v!=='' || $encodeEmptyStrings)
{
if($results!=='')
$results.=',';
$results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings);
}
}
return '{'.$results.'}';
}
else
{
foreach($value as $v)
{
if($v!=='' || $encodeEmptyStrings)
{
if($results!=='')
$results.=',';
$results.=self::encode($v,$toMap, $encodeEmptyStrings);
}
}
return '['.$results.']';
}
}
else if(is_integer($value))
return "$value";
else if(is_float($value))
{
switch($value)
{
case -INF:
return 'Number.NEGATIVE_INFINITY';
break;
case INF:
return 'Number.POSITIVE_INFINITY';
break;
default:
$locale=localeConv();
if($locale['decimal_point']=='.')
return "$value";
else
return str_replace($locale['decimal_point'], '.', "$value");
break;
}
}
else if(is_object($value))
if ($value instanceof TJavaScriptLiteral)
return $value->toJavaScriptLiteral();
else
return self::encode(get_object_vars($value),$toMap);
else if($value===null)
return 'null';
else
return '';
}
public static function jsonEncode($value, $options = 0)
{
if (is_string($value) &&
($g=Prado::getApplication()->getGlobalization(false))!==null &&
strtoupper($enc=$g->getCharset())!='UTF-8')
$value=iconv($enc, 'UTF-8', $value);
$s = json_encode($value,$options);
self::checkJsonError();
return $s;
}
public static function jsonDecode($value, $assoc = false, $depth = 512)
{
$s= json_decode($value, $assoc, $depth);
self::checkJsonError();
return $s;
}
private static function checkJsonError()
{
switch ($err = json_last_error())
{
case JSON_ERROR_NONE:
return;
break;
case JSON_ERROR_DEPTH:
$msg = 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = 'Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
$msg = 'Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$msg = 'Unknown error';
break;
}
throw new Exception("JSON error ($err): $msg");
}
public static function JSMin($code)
{
Prado::using('System.Web.Javascripts.JSMin');
return JSMin::minify($code);
}
}
class TUrlManager extends TModule
{
public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
{
$url=$serviceID.'='.urlencode($serviceParam);
$amp=$encodeAmpersand?'&':'&';
$request=$this->getRequest();
if(is_array($getItems) || $getItems instanceof Traversable)
{
if($encodeGetItems)
{
foreach($getItems as $name=>$value)
{
if(is_array($value))
{
$name=urlencode($name.'[]');
foreach($value as $v)
$url.=$amp.$name.'='.urlencode($v);
}
else
$url.=$amp.urlencode($name).'='.urlencode($value);
}
}
else
{
foreach($getItems as $name=>$value)
{
if(is_array($value))
{
foreach($value as $v)
$url.=$amp.$name.'[]='.$v;
}
else
$url.=$amp.$name.'='.$value;
}
}
}
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
{
const CGIFIX__PATH_INFO = 1;
const CGIFIX__SCRIPT_NAME = 2;
private $_urlManager=null;
private $_urlManagerID='';
private $_separator=',';
private $_serviceID=null;
private $_serviceParam=null;
private $_cookies=null;
private $_requestUri;
private $_pathInfo;
private $_cookieOnly=null;
private $_urlFormat=THttpRequestUrlFormat::Get;
private $_services;
private $_requestResolved=false;
private $_enableCookieValidation=false;
private $_cgiFix=0;
private $_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']='';
}
if(isset($_SERVER['REQUEST_URI']))
$this->_requestUri=$_SERVER['REQUEST_URI'];
else $this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
if($this->_cgiFix&self::CGIFIX__PATH_INFO && isset($_SERVER['ORIG_PATH_INFO']))
$this->_pathInfo=substr($_SERVER['ORIG_PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
elseif(isset($_SERVER['PATH_INFO']))
$this->_pathInfo=$_SERVER['PATH_INFO'];
else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
$this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
else
$this->_pathInfo='';
if(get_magic_quotes_gpc())
{
if(isset($_GET))
$_GET=$this->stripSlashes($_GET);
if(isset($_POST))
$_POST=$this->stripSlashes($_POST);
if(isset($_REQUEST))
$_REQUEST=$this->stripSlashes($_REQUEST);
if(isset($_COOKIE))
$_COOKIE=$this->stripSlashes($_COOKIE);
}
$this->getApplication()->setRequest($this);
}
public function stripSlashes(&$data)
{
return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
}
public function getUrl()
{
if($this->_url===null)
{
$secure=$this->getIsSecureConnection();
$url=$secure?'https://':'http://';
if(empty($_SERVER['HTTP_HOST']))
{
$url.=$_SERVER['SERVER_NAME'];
$port=$_SERVER['SERVER_PORT'];
if(($port!=80 && !$secure) || ($port!=443 && $secure))
$url.=':'.$port;
}
else
$url.=$_SERVER['HTTP_HOST'];
$url.=$this->getRequestUri();
$this->_url=new TUri($url);
}
return $this->_url;
}
public function 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 isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:null;
}
public function getContentType($mimetypeOnly = true)
{
if(!isset($_SERVER['CONTENT_TYPE']))
return null;
if($mimetypeOnly === true && ($_pos = strpos(';', $_SERVER['CONTENT_TYPE'])) !== false)
return substr($_SERVER['CONTENT_TYPE'], 0, $_pos);
return $_SERVER['CONTENT_TYPE'];
}
public function getIsSecureConnection()
{
return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
}
public function getPathInfo()
{
return $this->_pathInfo;
}
public function getQueryString()
{
return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:null;
}
public function getHttpProtocolVersion()
{
return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:null;
}
public function getHeaders($case=null)
{
static $result;
if($result === null && function_exists('apache_request_headers')) {
$result = apache_request_headers();
}
elseif($result === null) {
$result = array();
foreach($_SERVER as $key=>$value) {
if(strncasecmp($key, 'HTTP_', 5) !== 0) continue;
$key = str_replace(' ','-', ucwords(strtolower(str_replace('_',' ', substr($key, 5)))));
$result[$key] = $value;
}
}
if($case !== null)
return array_change_key_case($result, $case);
return $result;
}
public function getRequestUri()
{
return $this->_requestUri;
}
public function getBaseUrl($forceSecureConnection=null)
{
$url=$this->getUrl();
$scheme=($forceSecureConnection)?"https": (($forceSecureConnection === null)?$url->getScheme():'http');
$host=$url->getHost();
if (($port=$url->getPort())) $host.=':'.$port;
return $scheme.'://'.$host;
}
public function getApplicationUrl()
{
if($this->_cgiFix&self::CGIFIX__SCRIPT_NAME && isset($_SERVER['ORIG_SCRIPT_NAME']))
return $_SERVER['ORIG_SCRIPT_NAME'];
return isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:null;
}
public function getAbsoluteApplicationUrl($forceSecureConnection=null)
{
return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
}
public function getApplicationFilePath()
{
return realpath(isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:null);
}
public function getServerName()
{
return isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:null;
}
public function getServerPort()
{
return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null;
}
public function getUrlReferrer()
{
return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
}
public function getBrowser()
{
try
{
return get_browser();
}
catch(TPhpErrorException $e)
{
throw new TConfigurationException('httprequest_browscap_required');
}
}
public function getUserAgent()
{
return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
}
public function getUserHostAddress()
{
return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null;
}
public function getUserHost()
{
return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
}
public function getAcceptTypes()
{
return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
}
public function getUserLanguages()
{
return Prado::getUserLanguages();
}
public function getEnableCookieValidation()
{
return $this->_enableCookieValidation;
}
public function setEnableCookieValidation($value)
{
$this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
}
public function getCgiFix()
{
return $this->_cgiFix;
}
public function setCgiFix($value)
{
$this->_cgiFix=TPropertyValue::ensureInteger($value);
}
public function getCookies()
{
if($this->_cookies===null)
{
$this->_cookies=new THttpCookieCollection;
if($this->getEnableCookieValidation())
{
$sm=$this->getApplication()->getSecurityManager();
foreach($_COOKIE as $key=>$value)
{
if(($value=$sm->validateData($value))!==false)
$this->_cookies->add(new THttpCookie($key,$value));
}
}
else
{
foreach($_COOKIE as $key=>$value)
$this->_cookies->add(new THttpCookie($key,$value));
}
}
return $this->_cookies;
}
public function getUploadedFiles()
{
return $_FILES;
}
public function getServerVariables()
{
return $_SERVER;
}
public function getEnvironmentVariables()
{
return $_ENV;
}
public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
{
if ($this->_cookieOnly===null)
$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
$url=$this->_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;
private $_httpOnly=false;
public function __construct($name,$value)
{
$this->_name=$name;
$this->_value=$value;
}
public function getDomain()
{
return $this->_domain;
}
public function setDomain($value)
{
$this->_domain=$value;
}
public function getExpire()
{
return $this->_expire;
}
public function setExpire($value)
{
$this->_expire=TPropertyValue::ensureInteger($value);
}
public function getHttpOnly()
{
return $this->_httpOnly;
}
public function setHttpOnly($value)
{
$this->_httpOnly = TPropertyValue::ensureBoolean($value);
}
public function getName()
{
return $this->_name;
}
public function setName($value)
{
$this->_name=$value;
}
public function getValue()
{
return $this->_value;
}
public function setValue($value)
{
$this->_value=$value;
}
public function getPath()
{
return $this->_path;
}
public function setPath($value)
{
$this->_path=$value;
}
public function getSecure()
{
return $this->_secure;
}
public function setSecure($value)
{
$this->_secure=TPropertyValue::ensureBoolean($value);
}
}
class TUri extends TComponent
{
private static $_defaultPort=array(
'ftp'=>21,
'gopher'=>70,
'http'=>80,
'https'=>443,
'news'=>119,
'nntp'=>119,
'wais'=>210,
'telnet'=>23
);
private $_scheme;
private $_host;
private $_port;
private $_user;
private $_pass;
private $_path;
private $_query;
private $_fragment;
private $_uri;
public function __construct($uri)
{
if(($ret=@parse_url($uri))!==false)
{
$this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
$this->_host=isset($ret['host'])?$ret['host']:'';
$this->_port=isset($ret['port'])?$ret['port']:'';
$this->_user=isset($ret['user'])?$ret['user']:'';
$this->_pass=isset($ret['pass'])?$ret['pass']:'';
$this->_path=isset($ret['path'])?$ret['path']:'';
$this->_query=isset($ret['query'])?$ret['query']:'';
$this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
$this->_uri=$uri;
}
else
{
throw new TInvalidDataValueException('uri_format_invalid',$uri);
}
}
public function getUri()
{
return $this->_uri;
}
public function getScheme()
{
return $this->_scheme;
}
public function getHost()
{
return $this->_host;
}
public function getPort()
{
return $this->_port;
}
public function getUser()
{
return $this->_user;
}
public function getPassword()
{
return $this->_pass;
}
public function getPath()
{
return $this->_path;
}
public function getQuery()
{
return $this->_query;
}
public function getFragment()
{
return $this->_fragment;
}
}
class THttpRequestUrlFormat extends TEnumerable
{
const Get='Get';
const Path='Path';
}
class THttpResponseAdapter extends TApplicationComponent
{
private $_response;
public function __construct($response)
{
$this->_response=$response;
}
public function getResponse()
{
return $this->_response;
}
public function flushContent()
{
$this->_response->flushContent();
}
public function httpRedirect($url)
{
$this->_response->httpRedirect($url);
}
public function createNewHtmlWriter($type, $writer)
{
return $this->_response->createNewHtmlWriter($type,$writer);
}
}
class THttpResponse extends TModule implements ITextWriter
{
const DEFAULT_CONTENTTYPE = 'text/html';
const DEFAULT_CHARSET = 'UTF-8';
private static $HTTP_STATUS_CODES = array(
100 => 'Continue', 101 => 'Switching Protocols',
200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',
500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
);
private $_bufferOutput=true;
private $_initialized=false;
private $_cookies=null;
private $_status=200;
private $_reason='OK';
private $_htmlWriterType='System.Web.UI.THtmlWriter';
private $_contentType=null;
private $_charset='';
private $_adapter;
private $_httpHeaderSent;
private $_contentTypeHeaderSent;
public function __destruct()
{
}
public function setAdapter(THttpResponseAdapter $adapter)
{
$this->_adapter=$adapter;
}
public function getAdapter()
{
return $this->_adapter;
}
public function getHasAdapter()
{
return $this->_adapter!==null;
}
public function init($config)
{
if($this->_bufferOutput)
ob_start();
$this->_initialized=true;
$this->getApplication()->setResponse($this);
}
public function getCacheExpire()
{
return session_cache_expire();
}
public function setCacheExpire($value)
{
session_cache_expire(TPropertyValue::ensureInteger($value));
}
public function getCacheControl()
{
return session_cache_limiter();
}
public function setCacheControl($value)
{
session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
}
public function setContentType($type)
{
if ($this->_contentTypeHeaderSent)
throw new Exception('Unable to alter content-type as it has been already sent');
$this->_contentType = $type;
}
public function getContentType()
{
return $this->_contentType;
}
public function getCharset()
{
return $this->_charset;
}
public function setCharset($charset)
{
$this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
}
public function getBufferOutput()
{
return $this->_bufferOutput;
}
public function setBufferOutput($value)
{
if($this->_initialized)
throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
else
$this->_bufferOutput=TPropertyValue::ensureBoolean($value);
}
public function getStatusCode()
{
return $this->_status;
}
public function setStatusCode($status, $reason=null)
{
if ($this->_httpHeaderSent)
throw new Exception('Unable to alter response as HTTP header already sent');
$status=TPropertyValue::ensureInteger($status);
if(isset(self::$HTTP_STATUS_CODES[$status])) {
$this->_reason=self::$HTTP_STATUS_CODES[$status];
}else{
if($reason===null || $reason==='') {
throw new TInvalidDataValueException("response_status_reason_missing");
}
$reason=TPropertyValue::ensureString($reason);
if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
throw new TInvalidDataValueException("response_status_reason_barchars");
}
$this->_reason=$reason;
}
$this->_status=$status;
}
public function getStatusReason() {
return $this->_reason;
}
public function getCookies()
{
if($this->_cookies===null)
$this->_cookies=new THttpCookieCollection($this);
return $this->_cookies;
}
public function write($str)
{
if (!$this->_bufferOutput and !$this->_httpHeaderSent)
$this->ensureHeadersSent();
echo $str;
}
public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
{
static $defaultMimeTypes=array(
'css'=>'text/css',
'gif'=>'image/gif',
'png'=>'image/png',
'jpg'=>'image/jpeg',
'jpeg'=>'image/jpeg',
'htm'=>'text/html',
'html'=>'text/html',
'js'=>'javascript/js',
'pdf'=>'application/pdf',
'xls'=>'application/vnd.ms-excel',
);
if($mimeType===null)
{
$mimeType='text/plain';
if(function_exists('mime_content_type'))
$mimeType=mime_content_type($fileName);
else if(($ext=strrchr($fileName,'.'))!==false)
{
$ext=substr($ext,1);
if(isset($defaultMimeTypes[$ext]))
$mimeType=$defaultMimeTypes[$ext];
}
}
if($clientFileName===null)
$clientFileName=basename($fileName);
else
$clientFileName=basename($clientFileName);
if($fileSize===null || $fileSize < 0)
$fileSize = ($content===null?filesize($fileName):strlen($content));
$this->sendHttpHeader();
if(is_array($headers))
{
foreach($headers as $h)
header($h);
}
else
{
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Type: $mimeType");
$this->_contentTypeHeaderSent = true;
}
header('Content-Length: '.$fileSize);
header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
header('Content-Transfer-Encoding: binary');
if($content===null)
readfile($fileName);
else
echo $content;
}
public function redirect($url)
{
if($this->getHasAdapter())
$this->_adapter->httpRedirect($url);
else
$this->httpRedirect($url);
}
public function httpRedirect($url)
{
$this->ensureHeadersSent();
if($url[0]==='/')
$url=$this->getRequest()->getBaseUrl().$url;
if ($this->_status >= 300 && $this->_status < 400)
header('Location: '.str_replace('&','&',$url), true, $this->_status);
else
header('Location: '.str_replace('&','&',$url));
if(!$this->getApplication()->getRequestCompleted())
$this->getApplication()->onEndRequest();
exit();
}
public function reload()
{
$this->redirect($this->getRequest()->getRequestUri());
}
public function flush($continueBuffering = true)
{
if($this->getHasAdapter())
$this->_adapter->flushContent($continueBuffering);
else
$this->flushContent($continueBuffering);
}
public function ensureHeadersSent()
{
$this->ensureHttpHeaderSent();
$this->ensureContentTypeHeaderSent();
}
public function flushContent($continueBuffering = true)
{
$this->ensureHeadersSent();
if($this->_bufferOutput)
{
if (ob_get_length()>0)
{
if (!$continueBuffering)
{
$this->_bufferOutput = false;
ob_end_flush();
}
else
ob_flush();
flush();
}
}
else
flush();
}
protected function ensureHttpHeaderSent()
{
if (!$this->_httpHeaderSent)
$this->sendHttpHeader();
}
protected function sendHttpHeader()
{
if (($version=$this->getRequest()->getHttpProtocolVersion())==='')
header (' ', true, $this->_status);
else
header($version.' '.$this->_status.' '.$this->_reason, true, $this->_status);
$this->_httpHeaderSent = true;
}
protected function ensureContentTypeHeaderSent()
{
if (!$this->_contentTypeHeaderSent)
$this->sendContentTypeHeader();
}
protected function sendContentTypeHeader()
{
$contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
$charset=$this->getCharset();
if($charset === false) {
$this->appendHeader('Content-Type: '.$contentType);
return;
}
if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
$charset=$globalization->getCharset();
if($charset==='') $charset = self::DEFAULT_CHARSET;
$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
$this->_contentTypeHeaderSent = true;
}
public function getContents()
{
return $this->_bufferOutput?ob_get_contents():'';
}
public function clear()
{
if($this->_bufferOutput)
ob_clean();
}
public function getHeaders($case=null)
{
$result = array();
$headers = headers_list();
foreach($headers as $header) {
$tmp = explode(':', $header);
$key = trim(array_shift($tmp));
$value = trim(implode(':', $tmp));
if(isset($result[$key]))
$result[$key] .= ', ' . $value;
else
$result[$key] = $value;
}
if($case !== null)
return array_change_key_case($result, $case);
return $result;
}
public function appendHeader($value, $replace=true)
{
header($value, $replace);
}
public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
{
error_log($message,$messageType,$destination,$extraHeaders);
}
public function addCookie($cookie)
{
$request=$this->getRequest();
if($request->getEnableCookieValidation())
{
$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
setcookie(
$cookie->getName(),
$value,
$cookie->getExpire(),
$cookie->getPath(),
$cookie->getDomain(),
$cookie->getSecure(),
$cookie->getHttpOnly()
);
}
else {
setcookie(
$cookie->getName(),
$cookie->getValue(),
$cookie->getExpire(),
$cookie->getPath(),
$cookie->getDomain(),
$cookie->getSecure(),
$cookie->getHttpOnly()
);
}
}
public function removeCookie($cookie)
{
setcookie(
$cookie->getName(),
null,
0,
$cookie->getPath(),
$cookie->getDomain(),
$cookie->getSecure(),
$cookie->getHttpOnly()
);
}
public function getHtmlWriterType()
{
return $this->_htmlWriterType;
}
public function setHtmlWriterType($value)
{
$this->_htmlWriterType=$value;
}
public function createHtmlWriter($type=null)
{
if($type===null)
$type=$this->getHtmlWriterType();
if($this->getHasAdapter())
return $this->_adapter->createNewHtmlWriter($type, $this);
else
return $this->createNewHtmlWriter($type, $this);
}
public function createNewHtmlWriter($type, $writer)
{
return Prado::createComponent($type, $writer);
}
}
class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
{
private $_initialized=false;
private $_started=false;
private $_autoStart=false;
private $_cookie=null;
private $_id;
private $_customStorage=false;
public function getID()
{
return $this->_id;
}
public function setID($value)
{
$this->_id=$value;
}
public function init($config)
{
if($this->_autoStart)
$this->open();
$this->_initialized=true;
$this->getApplication()->setSession($this);
register_shutdown_function(array($this, "close"));
}
public function open()
{
if(!$this->_started)
{
if($this->_customStorage)
session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
if($this->_cookie!==null)
session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure());
if(ini_get('session.auto_start')!=='1')
session_start();
$this->_started=true;
}
}
public function close()
{
if($this->_started)
{
session_write_close();
$this->_started=false;
}
}
public function destroy()
{
if($this->_started)
{
session_destroy();
$this->_started=false;
}
}
public function regenerate($deleteOld=false)
{
$old = $this->getSessionID();
session_regenerate_id($deleteOld);
return $old;
}
public function getIsStarted()
{
return $this->_started;
}
public function getSessionID()
{
return session_id();
}
public function setSessionID($value)
{
if($this->_started)
throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
else
session_id($value);
}
public function getSessionName()
{
return session_name();
}
public function setSessionName($value)
{
if($this->_started)
throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
else if(ctype_alnum($value))
session_name($value);
else
throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
}
public function getSavePath()
{
return session_save_path();
}
public function setSavePath($value)
{
if($this->_started)
throw new TInvalidOperationException('httpsession_savepath_unchangeable');
else if(is_dir($value))
session_save_path($value);
else
throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
}
public function getUseCustomStorage()
{
return $this->_customStorage;
}
public function setUseCustomStorage($value)
{
$this->_customStorage=TPropertyValue::ensureBoolean($value);
}
public function getCookie()
{
if($this->_cookie===null)
$this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
return $this->_cookie;
}
public function getCookieMode()
{
if(ini_get('session.use_cookies')==='0')
return THttpSessionCookieMode::None;
else if(ini_get('session.use_only_cookies')==='0')
return THttpSessionCookieMode::Allow;
else
return THttpSessionCookieMode::Only;
}
public function setCookieMode($value)
{
if($this->_started)
throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
else
{
$value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
if($value===THttpSessionCookieMode::None)
ini_set('session.use_cookies','0');
else if($value===THttpSessionCookieMode::Allow)
{
ini_set('session.use_cookies','1');
ini_set('session.use_only_cookies','0');
}
else
{
ini_set('session.use_cookies','1');
ini_set('session.use_only_cookies','1');
ini_set('session.use_trans_sid', 0);
}
}
}
public function getAutoStart()
{
return $this->_autoStart;
}
public function setAutoStart($value)
{
if($this->_initialized)
throw new TInvalidOperationException('httpsession_autostart_unchangeable');
else
$this->_autoStart=TPropertyValue::ensureBoolean($value);
}
public function getGCProbability()
{
return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
}
public function setGCProbability($value)
{
if($this->_started)
throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
else
{
$value=TPropertyValue::ensureInteger($value);
if($value>=0 && $value<=100)
{
ini_set('session.gc_probability',$value);
ini_set('session.gc_divisor','100');
}
else
throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
}
}
public function getUseTransparentSessionID()
{
return ini_get('session.use_trans_sid')==='1';
}
public function setUseTransparentSessionID($value)
{
if($this->_started)
throw new TInvalidOperationException('httpsession_transid_unchangeable');
else
{
$value=TPropertyValue::ensureBoolean($value);
if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
throw new TInvalidOperationException('httpsession_transid_cookieonly');
ini_set('session.use_trans_sid',$value?'1':'0');
}
}
public function getTimeout()
{
return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
}
public function setTimeout($value)
{
if($this->_started)
throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
else
ini_set('session.gc_maxlifetime',$value);
}
public function _open($savePath,$sessionName)
{
return true;
}
public function _close()
{
return true;
}
public function _read($id)
{
return '';
}
public function _write($id,$data)
{
return true;
}
public function _destroy($id)
{
return true;
}
public function _gc($maxLifetime)
{
return true;
}
public function getIterator()
{
return new TSessionIterator;
}
public function getCount()
{
return count($_SESSION);
}
public function count()
{
return $this->getCount();
}
public function getKeys()
{
return array_keys($_SESSION);
}
public function itemAt($key)
{
return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
}
public function add($key,$value)
{
$_SESSION[$key]=$value;
}
public function remove($key)
{
if(isset($_SESSION[$key]))
{
$value=$_SESSION[$key];
unset($_SESSION[$key]);
return $value;
}
else
return null;
}
public function clear()
{
foreach(array_keys($_SESSION) as $key)
unset($_SESSION[$key]);
}
public function contains($key)
{
return isset($_SESSION[$key]);
}
public function toArray()
{
return $_SESSION;
}
public function offsetExists($offset)
{
return isset($_SESSION[$offset]);
}
public function offsetGet($offset)
{
return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
}
public function offsetSet($offset,$item)
{
$_SESSION[$offset]=$item;
}
public function offsetUnset($offset)
{
unset($_SESSION[$offset]);
}
}
class TSessionIterator implements Iterator
{
private $_keys;
private $_key;
public function __construct()
{
$this->_keys=array_keys($_SESSION);
}
public function rewind()
{
$this->_key=reset($this->_keys);
}
public function key()
{
return $this->_key;
}
public function current()
{
return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
}
public function next()
{
do
{
$this->_key=next($this->_keys);
}
while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
}
public function valid()
{
return $this->_key!==false;
}
}
class THttpSessionCookieMode extends TEnumerable
{
const None='None';
const Allow='Allow';
const Only='Only';
}
Prado::using('System.Web.UI.WebControls.*');
class TAttributeCollection extends TMap
{
private $_caseSensitive=false;
public function __get($name)
{
return $this->contains($name)?$this->itemAt($name):parent::__get($name);
}
public function __set($name,$value)
{
$this->add($name,$value);
}
public function getCaseSensitive()
{
return $this->_caseSensitive;
}
public function setCaseSensitive($value)
{
$this->_caseSensitive=TPropertyValue::ensureBoolean($value);
}
public function itemAt($key)
{
return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
}
public function add($key,$value)
{
parent::add($this->_caseSensitive?$key:strtolower($key),$value);
}
public function remove($key)
{
return parent::remove($this->_caseSensitive?$key:strtolower($key));
}
public function contains($key)
{
return parent::contains($this->_caseSensitive?$key:strtolower($key));
}
public function hasProperty($name)
{
return $this->contains($name) || parent::hasProperty($name);
}
public function canGetProperty($name)
{
return $this->contains($name) || parent::canGetProperty($name);
}
public function canSetProperty($name)
{
return true;
}
}
class TControlAdapter extends TApplicationComponent
{
protected $_control;
public function __construct($control)
{
$this->_control=$control;
}
public function getControl()
{
return $this->_control;
}
public function getPage()
{
return $this->_control?$this->_control->getPage():null;
}
public function createChildControls()
{
$this->_control->createChildControls();
}
public function loadState()
{
$this->_control->loadState();
}
public function saveState()
{
$this->_control->saveState();
}
public function onInit($param)
{
$this->_control->onInit($param);
}
public function onLoad($param)
{
$this->_control->onLoad($param);
}
public function onPreRender($param)
{
$this->_control->onPreRender($param);
}
public function onUnload($param)
{
$this->_control->onUnload($param);
}
public function render($writer)
{
$this->_control->render($writer);
}
public function renderChildren($writer)
{
$this->_control->renderChildren($writer);
}
}
class TControl extends TApplicationComponent implements IRenderable, IBindable
{
const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
const ID_SEPARATOR='$';
const CLIENT_ID_SEPARATOR='_';
const AUTOMATIC_ID_PREFIX='ctl';
const CS_CONSTRUCTED=0;
const CS_CHILD_INITIALIZED=1;
const CS_INITIALIZED=2;
const CS_STATE_LOADED=3;
const CS_LOADED=4;
const CS_PRERENDERED=5;
const IS_ID_SET=0x01;
const IS_DISABLE_VIEWSTATE=0x02;
const IS_SKIN_APPLIED=0x04;
const IS_STYLESHEET_APPLIED=0x08;
const IS_DISABLE_THEMING=0x10;
const IS_CHILD_CREATED=0x20;
const IS_CREATING_CHILD=0x40;
const RF_CONTROLS=0; const RF_CHILD_STATE=1; const RF_NAMED_CONTROLS=2; const RF_NAMED_CONTROLS_ID=3; const RF_SKIN_ID=4; const RF_DATA_BINDINGS=5; const RF_EVENTS=6; const RF_CONTROLSTATE=7; const RF_NAMED_OBJECTS=8; const RF_ADAPTER=9; const RF_AUTO_BINDINGS=10;
private $_id='';
private $_uid;
private $_parent;
private $_page;
private $_namingContainer;
private $_tplControl;
private $_viewState=array();
private $_tempState=array();
private $_trackViewState=true;
private $_stage=0;
private $_flags=0;
private $_rf=array();
public function __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 getIsSkinApplied()
{
return ($this->_flags & self::IS_SKIN_APPLIED);
}
public function getEnableTheming()
{
if($this->_flags & self::IS_DISABLE_THEMING)
return false;
else
return $this->_parent?$this->_parent->getEnableTheming():true;
}
public function setEnableTheming($value)
{
if($this->_stage>=self::CS_CHILD_INITIALIZED)
throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
else if(TPropertyValue::ensureBoolean($value))
$this->_flags &= ~self::IS_DISABLE_THEMING;
else
$this->_flags |= self::IS_DISABLE_THEMING;
}
public function getCustomData()
{
return $this->getViewState('CustomData',null);
}
public function setCustomData($value)
{
$this->setViewState('CustomData',$value,null);
}
public function getHasControls()
{
return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
}
public function getControls()
{
if(!isset($this->_rf[self::RF_CONTROLS]))
$this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
return $this->_rf[self::RF_CONTROLS];
}
protected function createControlCollection()
{
return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
}
public function getVisible($checkParents=true)
{
if($checkParents)
{
for($control=$this;$control;$control=$control->_parent)
if(!$control->getVisible(false))
return false;
return true;
}
else
return $this->getViewState('Visible',true);
}
public function setVisible($value)
{
$this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
}
public function getEnabled($checkParents=false)
{
if($checkParents)
{
for($control=$this;$control;$control=$control->_parent)
if(!$control->getViewState('Enabled',true))
return false;
return true;
}
else
return $this->getViewState('Enabled',true);
}
public function setEnabled($value)
{
$this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
}
public function getHasAttributes()
{
if($attributes=$this->getViewState('Attributes',null))
return $attributes->getCount()>0;
else
return false;
}
public function getAttributes()
{
if($attributes=$this->getViewState('Attributes',null))
return $attributes;
else
{
$attributes=new TAttributeCollection;
$this->setViewState('Attributes',$attributes,null);
return $attributes;
}
}
public function hasAttribute($name)
{
if($attributes=$this->getViewState('Attributes',null))
return $attributes->contains($name);
else
return false;
}
public function getAttribute($name)
{
if($attributes=$this->getViewState('Attributes',null))
return $attributes->itemAt($name);
else
return null;
}
public function setAttribute($name,$value)
{
$this->getAttributes()->add($name,$value);
}
public function removeAttribute($name)
{
if($attributes=$this->getViewState('Attributes',null))
return $attributes->remove($name);
else
return null;
}
public function getEnableViewState($checkParents=false)
{
if($checkParents)
{
for($control=$this;$control!==null;$control=$control->getParent())
if($control->_flags & self::IS_DISABLE_VIEWSTATE)
return false;
return true;
}
else
return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
}
public function setEnableViewState($value)
{
if(TPropertyValue::ensureBoolean($value))
$this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
else
$this->_flags |= self::IS_DISABLE_VIEWSTATE;
}
protected function getControlState($key,$defaultValue=null)
{
return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
}
protected function setControlState($key,$value,$defaultValue=null)
{
if($value===$defaultValue)
unset($this->_rf[self::RF_CONTROLSTATE][$key]);
else
$this->_rf[self::RF_CONTROLSTATE][$key]=$value;
}
protected function clearControlState($key)
{
unset($this->_rf[self::RF_CONTROLSTATE][$key]);
}
public function trackViewState($enabled)
{
$this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
}
public function getViewState($key,$defaultValue=null)
{
if(isset($this->_viewState[$key]))
return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
else if(isset($this->_tempState[$key]))
{
if(is_object($this->_tempState[$key]) && $this->_trackViewState)
$this->_viewState[$key]=$this->_tempState[$key];
return $this->_tempState[$key];
}
else
return $defaultValue;
}
public function setViewState($key,$value,$defaultValue=null)
{
if($this->_trackViewState)
{
$this->_viewState[$key]=$value;
unset($this->_tempState[$key]);
}
else
{
unset($this->_viewState[$key]);
$this->_tempState[$key]=$value;
}
}
public function clearViewState($key)
{
unset($this->_viewState[$key]);
unset($this->_tempState[$key]);
}
public function bindProperty($name,$expression)
{
$this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
}
public function unbindProperty($name)
{
unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
}
public function autoBindProperty($name,$expression)
{
$this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
}
public function dataBind()
{
$this->dataBindProperties();
$this->onDataBinding(null);
$this->dataBindChildren();
}
protected function dataBindProperties()
{
if(isset($this->_rf[self::RF_DATA_BINDINGS]))
{
if(($context=$this->getTemplateControl())===null)
$context=$this;
foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
$this->setSubProperty($property,$context->evaluateExpression($expression));
}
}
protected function autoDataBindProperties()
{
if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
{
if(($context=$this->getTemplateControl())===null)
$context=$this;
foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
$this->setSubProperty($property,$context->evaluateExpression($expression));
}
}
protected function dataBindChildren()
{
if(isset($this->_rf[self::RF_CONTROLS]))
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
if($control instanceof IBindable)
$control->dataBind();
}
}
final protected function getChildControlsCreated()
{
return ($this->_flags & self::IS_CHILD_CREATED)!==0;
}
final protected function setChildControlsCreated($value)
{
if($value)
$this->_flags |= self::IS_CHILD_CREATED;
else
{
if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
$this->getControls()->clear();
$this->_flags &= ~self::IS_CHILD_CREATED;
}
}
public function ensureChildControls()
{
if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
{
try
{
$this->_flags |= self::IS_CREATING_CHILD;
if(isset($this->_rf[self::RF_ADAPTER]))
$this->_rf[self::RF_ADAPTER]->createChildControls();
else
$this->createChildControls();
$this->_flags &= ~self::IS_CREATING_CHILD;
$this->_flags |= self::IS_CHILD_CREATED;
}
catch(Exception $e)
{
$this->_flags &= ~self::IS_CREATING_CHILD;
$this->_flags |= self::IS_CHILD_CREATED;
throw $e;
}
}
}
public function createChildControls()
{
}
public function findControl($id)
{
$id=strtr($id,'.',self::ID_SEPARATOR);
$container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
if(!$container || !$container->getHasControls())
return null;
if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
{
$container->_rf[self::RF_NAMED_CONTROLS]=array();
$container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
}
if(($pos=strpos($id,self::ID_SEPARATOR))===false)
return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
else
{
$cid=substr($id,0,$pos);
$sid=substr($id,$pos+1);
if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
else
return null;
}
}
public function findControlsByType($type,$strict=true)
{
$controls=array();
if($this->getHasControls())
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
{
if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
$controls[]=$control;
if(($control instanceof TControl) && $control->getHasControls())
$controls=array_merge($controls,$control->findControlsByType($type,$strict));
}
}
return $controls;
}
public function findControlsByID($id)
{
$controls=array();
if($this->getHasControls())
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
{
if($control instanceof TControl)
{
if($control->_id===$id)
$controls[]=$control;
$controls=array_merge($controls,$control->findControlsByID($id));
}
}
}
return $controls;
}
public function clearNamingContainer()
{
unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
$this->clearNameTable();
}
public function registerObject($name,$object)
{
if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
throw new TInvalidOperationException('control_object_reregistered',$name);
$this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
}
public function unregisterObject($name)
{
unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
}
public function isObjectRegistered($name)
{
return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
}
public function getHasChildInitialized()
{
return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
}
public function getHasInitialized()
{
return $this->getControlStage() >= self::CS_INITIALIZED;
}
public function getHasLoadedPostData()
{
return $this->getControlStage() >= self::CS_STATE_LOADED;
}
public function getHasLoaded()
{
return $this->getControlStage() >= self::CS_LOADED;
}
public function getHasPreRendered()
{
return $this->getControlStage() >= self::CS_PRERENDERED;
}
public function getRegisteredObject($name)
{
return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
}
public function getAllowChildControls()
{
return true;
}
public function addParsedObject($object)
{
$this->getControls()->add($object);
}
final protected function clearChildState()
{
unset($this->_rf[self::RF_CHILD_STATE]);
}
final protected function isDescendentOf($ancestor)
{
$control=$this;
while($control!==$ancestor && $control->_parent)
$control=$control->_parent;
return $control===$ancestor;
}
public function addedControl($control)
{
if($control->_parent)
$control->_parent->getControls()->remove($control);
$control->_parent=$this;
$control->_page=$this->getPage();
$namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
if($namingContainer)
{
$control->_namingContainer=$namingContainer;
if($control->_id==='')
$control->generateAutomaticID();
else
$namingContainer->clearNameTable();
$control->clearCachedUniqueID($control instanceof INamingContainer);
}
if($this->_stage>=self::CS_CHILD_INITIALIZED)
{
$control->initRecursive($namingContainer);
if($this->_stage>=self::CS_STATE_LOADED)
{
if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
{
$state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
}
else
$state=null;
$control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
if($this->_stage>=self::CS_LOADED)
{
$control->loadRecursive();
if($this->_stage>=self::CS_PRERENDERED)
$control->preRenderRecursive();
}
}
}
}
public function removedControl($control)
{
if($this->_namingContainer)
$this->_namingContainer->clearNameTable();
$control->unloadRecursive();
$control->_parent=null;
$control->_page=null;
$control->_namingContainer=null;
$control->_tplControl=null;
if(!($control->_flags & self::IS_ID_SET))
$control->_id='';
else
unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
$control->clearCachedUniqueID(true);
}
protected function initRecursive($namingContainer=null)
{
$this->ensureChildControls();
if($this->getHasControls())
{
if($this instanceof INamingContainer)
$namingContainer=$this;
$page=$this->getPage();
foreach($this->_rf[self::RF_CONTROLS] as $control)
{
if($control instanceof TControl)
{
$control->_namingContainer=$namingContainer;
$control->_page=$page;
if($control->_id==='' && $namingContainer)
$control->generateAutomaticID();
$control->initRecursive($namingContainer);
}
}
}
if($this->_stage_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 instanceof IActiveControl || $this->getVisible(false))
{
if(isset($this->_rf[self::RF_ADAPTER]))
$this->_rf[self::RF_ADAPTER]->render($writer);
else
$this->render($writer);
}
}
public function render($writer)
{
$this->renderChildren($writer);
}
public function renderChildren($writer)
{
if($this->getHasControls())
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
{
if(is_string($control))
$writer->write($control);
else if($control instanceof TControl)
$control->renderControl($writer);
else if($control instanceof IRenderable)
$control->render($writer);
}
}
}
public function saveState()
{
}
public function loadState()
{
}
protected function loadStateRecursive(&$state,$needViewState=true)
{
if(is_array($state))
{
$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
if(isset($state[1]))
{
$this->_rf[self::RF_CONTROLSTATE]=&$state[1];
unset($state[1]);
}
else
unset($this->_rf[self::RF_CONTROLSTATE]);
if($needViewState)
{
if(isset($state[0]))
$this->_viewState=&$state[0];
else
$this->_viewState=array();
}
unset($state[0]);
if($this->getHasControls())
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
{
if($control instanceof TControl)
{
if(isset($state[$control->_id]))
{
$control->loadStateRecursive($state[$control->_id],$needViewState);
unset($state[$control->_id]);
}
}
}
}
if(!empty($state))
$this->_rf[self::RF_CHILD_STATE]=&$state;
}
$this->_stage=self::CS_STATE_LOADED;
if(isset($this->_rf[self::RF_ADAPTER]))
$this->_rf[self::RF_ADAPTER]->loadState();
else
$this->loadState();
}
protected function &saveStateRecursive($needViewState=true)
{
if(isset($this->_rf[self::RF_ADAPTER]))
$this->_rf[self::RF_ADAPTER]->saveState();
else
$this->saveState();
$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
$state=array();
if($this->getHasControls())
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
{
if($control instanceof TControl)
$state[$control->_id]=&$control->saveStateRecursive($needViewState);
}
}
if($needViewState && !empty($this->_viewState))
$state[0]=&$this->_viewState;
if(isset($this->_rf[self::RF_CONTROLSTATE]))
$state[1]=&$this->_rf[self::RF_CONTROLSTATE];
return $state;
}
public function applyStyleSheetSkin($page)
{
if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
{
$page->applyControlStyleSheet($this);
$this->_flags |= self::IS_STYLESHEET_APPLIED;
}
else if($this->_flags & self::IS_STYLESHEET_APPLIED)
throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
}
private function clearCachedUniqueID($recursive)
{
if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
{
foreach($this->_rf[self::RF_CONTROLS] as $control)
if($control instanceof TControl)
$control->clearCachedUniqueID($recursive);
}
$this->_uid=null;
}
private function generateAutomaticID()
{
$this->_flags &= ~self::IS_ID_SET;
if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
$id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
$this->_id=self::AUTOMATIC_ID_PREFIX . $id;
$this->_namingContainer->clearNameTable();
}
private function clearNameTable()
{
unset($this->_rf[self::RF_NAMED_CONTROLS]);
}
private function fillNameTable($container,$controls)
{
foreach($controls as $control)
{
if($control instanceof TControl)
{
if($control->_id!=='')
{
if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
else
$container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
}
if(!($control instanceof INamingContainer) && $control->getHasControls())
$this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
}
}
}
}
class TControlCollection extends TList
{
private $_o;
public function __construct(TControl $owner,$readOnly=false)
{
$this->_o=$owner;
parent::__construct(null,$readOnly);
}
protected function getOwner()
{
return $this->_o;
}
public function insertAt($index,$item)
{
if($item instanceof TControl)
{
parent::insertAt($index,$item);
$this->_o->addedControl($item);
}
else if(is_string($item) || ($item instanceof IRenderable))
parent::insertAt($index,$item);
else
throw new TInvalidDataTypeException('controlcollection_control_required');
}
public function removeAt($index)
{
$item=parent::removeAt($index);
if($item instanceof TControl)
$this->_o->removedControl($item);
return $item;
}
public function clear()
{
parent::clear();
if($this->_o instanceof INamingContainer)
$this->_o->clearNamingContainer();
}
}
class TEmptyControlCollection extends TControlCollection
{
public function __construct(TControl $owner)
{
parent::__construct($owner,true);
}
public function insertAt($index,$item)
{
if(!is_string($item)) parent::insertAt($index,$item); }
}
interface INamingContainer
{
}
interface IPostBackEventHandler
{
public function raisePostBackEvent($param);
}
interface IPostBackDataHandler
{
public function loadPostData($key,$values);
public function raisePostDataChangedEvent();
public function getDataChanged();
}
interface IValidator
{
public function validate();
public function getIsValid();
public function setIsValid($value);
public function getErrorMessage();
public function setErrorMessage($value);
}
interface IValidatable
{
public function getValidationPropertyValue();
public function getIsValid();
public function setIsValid($value);
}
interface IBroadcastEventReceiver
{
public function broadcastEventReceived($sender,$param);
}
interface ITheme
{
public function applySkin($control);
}
interface ITemplate
{
public function instantiateIn($parent);
}
interface IButtonControl
{
public function getText();
public function setText($value);
public function getCausesValidation();
public function setCausesValidation($value);
public function getCommandName();
public function setCommandName($value);
public function getCommandParameter();
public function setCommandParameter($value);
public function getValidationGroup();
public function setValidationGroup($value);
public function onClick($param);
public function onCommand($param);
public function setIsDefaultButton($value);
public function getIsDefaultButton();
}
interface ISurroundable
{
public function getSurroundingTagID();
}
class TBroadcastEventParameter extends TEventParameter
{
private $_name;
private $_param;
public function __construct($name='',$parameter=null)
{
$this->_name=$name;
$this->_param=$parameter;
}
public function getName()
{
return $this->_name;
}
public function setName($value)
{
$this->_name=$value;
}
public function getParameter()
{
return $this->_param;
}
public function setParameter($value)
{
$this->_param=$value;
}
}
class TCommandEventParameter extends TEventParameter
{
private $_name;
private $_param;
public function __construct($name='',$parameter='')
{
$this->_name=$name;
$this->_param=$parameter;
}
public function getCommandName()
{
return $this->_name;
}
public function getCommandParameter()
{
return $this->_param;
}
}
class TCompositeLiteral extends TComponent implements IRenderable, IBindable
{
const TYPE_EXPRESSION=0;
const TYPE_STATEMENTS=1;
const TYPE_DATABINDING=2;
private $_container=null;
private $_items=array();
private $_expressions=array();
private $_statements=array();
private $_bindings=array();
public function __construct($items)
{
$this->_items=array();
$this->_expressions=array();
$this->_statements=array();
foreach($items as $id=>$item)
{
if(is_array($item))
{
if($item[0]===self::TYPE_EXPRESSION)
$this->_expressions[$id]=$item[1];
else if($item[0]===self::TYPE_STATEMENTS)
$this->_statements[$id]=$item[1];
else if($item[0]===self::TYPE_DATABINDING)
$this->_bindings[$id]=$item[1];
$this->_items[$id]='';
}
else
$this->_items[$id]=$item;
}
}
public function getContainer()
{
return $this->_container;
}
public function setContainer(TComponent $value)
{
$this->_container=$value;
}
public function evaluateDynamicContent()
{
$context=$this->_container===null?$this:$this->_container;
foreach($this->_expressions as $id=>$expression)
$this->_items[$id]=$context->evaluateExpression($expression);
foreach($this->_statements as $id=>$statement)
$this->_items[$id]=$context->evaluateStatements($statement);
}
public function dataBind()
{
$context=$this->_container===null?$this:$this->_container;
foreach($this->_bindings as $id=>$binding)
$this->_items[$id]=$context->evaluateExpression($binding);
}
public function render($writer)
{
$writer->write(implode('',$this->_items));
}
}
class TFont extends TComponent
{
const IS_BOLD=0x01;
const IS_ITALIC=0x02;
const IS_OVERLINE=0x04;
const IS_STRIKEOUT=0x08;
const IS_UNDERLINE=0x10;
const IS_SET_BOLD=0x01000;
const IS_SET_ITALIC=0x02000;
const IS_SET_OVERLINE=0x04000;
const IS_SET_STRIKEOUT=0x08000;
const IS_SET_UNDERLINE=0x10000;
const IS_SET_SIZE=0x20000;
const IS_SET_NAME=0x40000;
private $_flags=0;
private $_name='';
private $_size='';
public function getBold()
{
return ($this->_flags & self::IS_BOLD)!==0;
}
public function setBold($value)
{
$this->_flags |= self::IS_SET_BOLD;
if(TPropertyValue::ensureBoolean($value))
$this->_flags |= self::IS_BOLD;
else
$this->_flags &= ~self::IS_BOLD;
}
public function getItalic()
{
return ($this->_flags & self::IS_ITALIC)!==0;
}
public function setItalic($value)
{
$this->_flags |= self::IS_SET_ITALIC;
if(TPropertyValue::ensureBoolean($value))
$this->_flags |= self::IS_ITALIC;
else
$this->_flags &= ~self::IS_ITALIC;
}
public function getOverline()
{
return ($this->_flags & self::IS_OVERLINE)!==0;
}
public function setOverline($value)
{
$this->_flags |= self::IS_SET_OVERLINE;
if(TPropertyValue::ensureBoolean($value))
$this->_flags |= self::IS_OVERLINE;
else
$this->_flags &= ~self::IS_OVERLINE;
}
public function getSize()
{
return $this->_size;
}
public function setSize($value)
{
$this->_flags |= self::IS_SET_SIZE;
$this->_size=$value;
}
public function getStrikeout()
{
return ($this->_flags & self::IS_STRIKEOUT)!==0;
}
public function setStrikeout($value)
{
$this->_flags |= self::IS_SET_STRIKEOUT;
if(TPropertyValue::ensureBoolean($value))
$this->_flags |= self::IS_STRIKEOUT;
else
$this->_flags &= ~self::IS_STRIKEOUT;
}
public function getUnderline()
{
return ($this->_flags & self::IS_UNDERLINE)!==0;
}
public function setUnderline($value)
{
$this->_flags |= self::IS_SET_UNDERLINE;
if(TPropertyValue::ensureBoolean($value))
$this->_flags |= self::IS_UNDERLINE;
else
$this->_flags &= ~self::IS_UNDERLINE;
}
public function getName()
{
return $this->_name;
}
public function setName($value)
{
$this->_flags |= self::IS_SET_NAME;
$this->_name=$value;
}
public function getIsEmpty()
{
return !$this->_flags;
}
public function reset()
{
$this->_flags=0;
$this->_name='';
$this->_size='';
}
public function mergeWith($font)
{
if($font===null || $font->_flags===0)
return;
if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
$this->setBold($font->getBold());
if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
$this->setItalic($font->getItalic());
if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
$this->setOverline($font->getOverline());
if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
$this->setStrikeout($font->getStrikeout());
if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
$this->setUnderline($font->getUnderline());
if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
$this->setSize($font->getSize());
if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
$this->setName($font->getName());
}
public function copyFrom($font)
{
if($font===null || $font->_flags===0)
return;
if($font->_flags & self::IS_SET_BOLD)
$this->setBold($font->getBold());
if($font->_flags & self::IS_SET_ITALIC)
$this->setItalic($font->getItalic());
if($font->_flags & self::IS_SET_OVERLINE)
$this->setOverline($font->getOverline());
if($font->_flags & self::IS_SET_STRIKEOUT)
$this->setStrikeout($font->getStrikeout());
if($font->_flags & self::IS_SET_UNDERLINE)
$this->setUnderline($font->getUnderline());
if($font->_flags & self::IS_SET_SIZE)
$this->setSize($font->getSize());
if($font->_flags & self::IS_SET_NAME)
$this->setName($font->getName());
}
public function toString()
{
if($this->_flags===0)
return '';
$str='';
if($this->_flags & self::IS_SET_BOLD)
$str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
if($this->_flags & self::IS_SET_ITALIC)
$str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
$textDec='';
if($this->_flags & self::IS_UNDERLINE)
$textDec.='underline';
if($this->_flags & self::IS_OVERLINE)
$textDec.=' overline';
if($this->_flags & self::IS_STRIKEOUT)
$textDec.=' line-through';
$textDec=ltrim($textDec);
if($textDec!=='')
$str.='text-decoration:'.$textDec.';';
if($this->_size!=='')
$str.='font-size:'.$this->_size.';';
if($this->_name!=='')
$str.='font-family:'.$this->_name.';';
return $str;
}
public function addAttributesToRender($writer)
{
if($this->_flags===0)
return;
if($this->_flags & self::IS_SET_BOLD)
$writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
if($this->_flags & self::IS_SET_ITALIC)
$writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
$textDec='';
if($this->_flags & self::IS_UNDERLINE)
$textDec.='underline';
if($this->_flags & self::IS_OVERLINE)
$textDec.=' overline';
if($this->_flags & self::IS_STRIKEOUT)
$textDec.=' line-through';
$textDec=ltrim($textDec);
if($textDec!=='')
$writer->addStyleAttribute('text-decoration',$textDec);
if($this->_size!=='')
$writer->addStyleAttribute('font-size',$this->_size);
if($this->_name!=='')
$writer->addStyleAttribute('font-family',$this->_name);
}
}
class TStyle extends TComponent
{
private $_fields=array();
private $_font=null;
private $_class=null;
private $_customStyle=null;
private $_displayStyle='Fixed';
public function __construct($style=null)
{
if($style!==null)
$this->copyFrom($style);
}
public function __clone()
{
if($this->_font!==null)
$this->_font = clone($this->_font);
}
public function getBackColor()
{
return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
}
public function setBackColor($value)
{
if(trim($value)==='')
unset($this->_fields['background-color']);
else
$this->_fields['background-color']=$value;
}
public function getBorderColor()
{
return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
}
public function setBorderColor($value)
{
if(trim($value)==='')
unset($this->_fields['border-color']);
else
$this->_fields['border-color']=$value;
}
public function getBorderStyle()
{
return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
}
public function setBorderStyle($value)
{
if(trim($value)==='')
unset($this->_fields['border-style']);
else
$this->_fields['border-style']=$value;
}
public function getBorderWidth()
{
return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
}
public function setBorderWidth($value)
{
if(trim($value)==='')
unset($this->_fields['border-width']);
else
$this->_fields['border-width']=$value;
}
public function getCssClass()
{
return $this->_class===null?'':$this->_class;
}
public function hasCssClass()
{
return ($this->_class!==null);
}
public function setCssClass($value)
{
$this->_class=$value;
}
public function getFont()
{
if($this->_font===null)
$this->_font=new TFont;
return $this->_font;
}
public function hasFont()
{
return $this->_font !== null;
}
public function setDisplayStyle($value)
{
$this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
switch($this->_displayStyle)
{
case TDisplayStyle::None:
$this->_fields['display'] = 'none';
break;
case TDisplayStyle::Dynamic:
$this->_fields['display'] = ''; break;
case TDisplayStyle::Fixed:
$this->_fields['visibility'] = 'visible';
break;
case TDisplayStyle::Hidden:
$this->_fields['visibility'] = 'hidden';
break;
}
}
public function getDisplayStyle()
{
return $this->_displayStyle;
}
public function getForeColor()
{
return isset($this->_fields['color'])?$this->_fields['color']:'';
}
public function setForeColor($value)
{
if(trim($value)==='')
unset($this->_fields['color']);
else
$this->_fields['color']=$value;
}
public function getHeight()
{
return isset($this->_fields['height'])?$this->_fields['height']:'';
}
public function setHeight($value)
{
if(trim($value)==='')
unset($this->_fields['height']);
else
$this->_fields['height']=$value;
}
public function getCustomStyle()
{
return $this->_customStyle===null?'':$this->_customStyle;
}
public function setCustomStyle($value)
{
$this->_customStyle=$value;
}
public function getStyleField($name)
{
return isset($this->_fields[$name])?$this->_fields[$name]:'';
}
public function setStyleField($name,$value)
{
$this->_fields[$name]=$value;
}
public function clearStyleField($name)
{
unset($this->_fields[$name]);
}
public function hasStyleField($name)
{
return isset($this->_fields[$name]);
}
public function getWidth()
{
return isset($this->_fields['width'])?$this->_fields['width']:'';
}
public function setWidth($value)
{
$this->_fields['width']=$value;
}
public function reset()
{
$this->_fields=array();
$this->_font=null;
$this->_class=null;
$this->_customStyle=null;
}
public function copyFrom($style)
{
if($style instanceof TStyle)
{
$this->_fields=array_merge($this->_fields,$style->_fields);
if($style->_class!==null)
$this->_class=$style->_class;
if($style->_customStyle!==null)
$this->_customStyle=$style->_customStyle;
if($style->_font!==null)
$this->getFont()->copyFrom($style->_font);
}
}
public function mergeWith($style)
{
if($style instanceof TStyle)
{
$this->_fields=array_merge($style->_fields,$this->_fields);
if($this->_class===null)
$this->_class=$style->_class;
if($this->_customStyle===null)
$this->_customStyle=$style->_customStyle;
if($style->_font!==null)
$this->getFont()->mergeWith($style->_font);
}
}
public function addAttributesToRender($writer)
{
if($this->_customStyle!==null)
{
foreach(explode(';',$this->_customStyle) as $style)
{
$arr=explode(':',$style,2);
if(isset($arr[1]) && trim($arr[0])!=='')
$writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
}
}
$writer->addStyleAttributes($this->_fields);
if($this->_font!==null)
$this->_font->addAttributesToRender($writer);
if($this->_class!==null)
$writer->addAttribute('class',$this->_class);
}
public function getStyleFields()
{
return $this->_fields;
}
}
class TDisplayStyle extends TEnumerable
{
const None='None';
const Dynamic='Dynamic';
const Fixed='Fixed';
const Hidden='Hidden';
}
class TTableStyle extends TStyle
{
private $_backImageUrl=null;
private $_horizontalAlign=null;
private $_cellPadding=null;
private $_cellSpacing=null;
private $_gridLines=null;
private $_borderCollapse=null;
public function reset()
{
$this->_backImageUrl=null;
$this->_horizontalAlign=null;
$this->_cellPadding=null;
$this->_cellSpacing=null;
$this->_gridLines=null;
$this->_borderCollapse=null;
}
public function copyFrom($style)
{
parent::copyFrom($style);
if($style instanceof TTableStyle)
{
if($style->_backImageUrl!==null)
$this->_backImageUrl=$style->_backImageUrl;
if($style->_horizontalAlign!==null)
$this->_horizontalAlign=$style->_horizontalAlign;
if($style->_cellPadding!==null)
$this->_cellPadding=$style->_cellPadding;
if($style->_cellSpacing!==null)
$this->_cellSpacing=$style->_cellSpacing;
if($style->_gridLines!==null)
$this->_gridLines=$style->_gridLines;
if($style->_borderCollapse!==null)
$this->_borderCollapse=$style->_borderCollapse;
}
}
public function mergeWith($style)
{
parent::mergeWith($style);
if($style instanceof TTableStyle)
{
if($this->_backImageUrl===null && $style->_backImageUrl!==null)
$this->_backImageUrl=$style->_backImageUrl;
if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
$this->_horizontalAlign=$style->_horizontalAlign;
if($this->_cellPadding===null && $style->_cellPadding!==null)
$this->_cellPadding=$style->_cellPadding;
if($this->_cellSpacing===null && $style->_cellSpacing!==null)
$this->_cellSpacing=$style->_cellSpacing;
if($this->_gridLines===null && $style->_gridLines!==null)
$this->_gridLines=$style->_gridLines;
if($this->_borderCollapse===null && $style->_borderCollapse!==null)
$this->_borderCollapse=$style->_borderCollapse;
}
}
public function addAttributesToRender($writer)
{
if(($url=trim($this->getBackImageUrl()))!=='')
$writer->addStyleAttribute('background-image','url('.$url.')');
if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
$writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
if(($cellPadding=$this->getCellPadding())>=0)
$writer->addAttribute('cellpadding',"$cellPadding");
if(($cellSpacing=$this->getCellSpacing())>=0)
$writer->addAttribute('cellspacing',"$cellSpacing");
if($this->getBorderCollapse())
$writer->addStyleAttribute('border-collapse','collapse');
switch($this->getGridLines())
{
case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
}
parent::addAttributesToRender($writer);
}
public function getBackImageUrl()
{
return $this->_backImageUrl===null?'':$this->_backImageUrl;
}
public function setBackImageUrl($value)
{
$this->_backImageUrl=$value;
}
public function getHorizontalAlign()
{
return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
}
public function setHorizontalAlign($value)
{
$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
}
public function getCellPadding()
{
return $this->_cellPadding===null?-1:$this->_cellPadding;
}
public function setCellPadding($value)
{
if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
}
public function getCellSpacing()
{
return $this->_cellSpacing===null?-1:$this->_cellSpacing;
}
public function setCellSpacing($value)
{
if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
}
public function getGridLines()
{
return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
}
public function setGridLines($value)
{
$this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
}
public function getBorderCollapse()
{
return $this->_borderCollapse===null?false:$this->_borderCollapse;
}
public function setBorderCollapse($value)
{
$this->_borderCollapse=TPropertyValue::ensureBoolean($value);
}
}
class TTableItemStyle extends TStyle
{
private $_horizontalAlign=null;
private $_verticalAlign=null;
private $_wrap=null;
public function reset()
{
parent::reset();
$this->_verticalAlign=null;
$this->_horizontalAlign=null;
$this->_wrap=null;
}
public function copyFrom($style)
{
parent::copyFrom($style);
if($style instanceof TTableItemStyle)
{
if($this->_verticalAlign===null && $style->_verticalAlign!==null)
$this->_verticalAlign=$style->_verticalAlign;
if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
$this->_horizontalAlign=$style->_horizontalAlign;
if($this->_wrap===null && $style->_wrap!==null)
$this->_wrap=$style->_wrap;
}
}
public function mergeWith($style)
{
parent::mergeWith($style);
if($style instanceof TTableItemStyle)
{
if($style->_verticalAlign!==null)
$this->_verticalAlign=$style->_verticalAlign;
if($style->_horizontalAlign!==null)
$this->_horizontalAlign=$style->_horizontalAlign;
if($style->_wrap!==null)
$this->_wrap=$style->_wrap;
}
}
public function addAttributesToRender($writer)
{
if(!$this->getWrap())
$writer->addStyleAttribute('white-space','nowrap');
if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
$writer->addAttribute('align',strtolower($horizontalAlign));
if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
$writer->addAttribute('valign',strtolower($verticalAlign));
parent::addAttributesToRender($writer);
}
public function getHorizontalAlign()
{
return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
}
public function setHorizontalAlign($value)
{
$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
}
public function getVerticalAlign()
{
return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
}
public function setVerticalAlign($value)
{
$this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
}
public function getWrap()
{
return $this->_wrap===null?true:$this->_wrap;
}
public function setWrap($value)
{
$this->_wrap=TPropertyValue::ensureBoolean($value);
}
}
class THorizontalAlign extends TEnumerable
{
const NotSet='NotSet';
const Left='Left';
const Right='Right';
const Center='Center';
const Justify='Justify';
}
class TVerticalAlign extends TEnumerable
{
const NotSet='NotSet';
const Top='Top';
const Bottom='Bottom';
const Middle='Middle';
}
class TTableGridLines extends TEnumerable
{
const None='None';
const Horizontal='Horizontal';
const Vertical='Vertical';
const Both='Both';
}
class TWebControlAdapter extends TControlAdapter
{
public function render($writer)
{
$this->renderBeginTag($writer);
$this->renderContents($writer);
$this->renderEndTag($writer);
}
public function renderBeginTag($writer)
{
$this->getControl()->renderBeginTag($writer);
}
public function renderContents($writer)
{
$this->getControl()->renderContents($writer);
}
public function renderEndTag($writer)
{
$this->getControl()->renderEndTag($writer);
}
}
class TWebControlDecorator extends TComponent {
private $_internalonly;
private $_usestate = false;
private $_control;
private $_outercontrol;
private $_addedTemplateDecoration=false;
private $_pretagtext = '';
private $_precontentstext = '';
private $_postcontentstext = '';
private $_posttagtext = '';
private $_pretagtemplate;
private $_precontentstemplate;
private $_postcontentstemplate;
private $_posttagtemplate;
public function __construct($control, $onlyinternal = false) {
$this->_control = $control;
$this->_internalonly = $onlyinternal;
}
public function getUseState()
{
return $this->_usestate;
}
public function setUseState($value)
{
$this->_usestate = TPropertyValue::ensureBoolean($value);
}
public function getPreTagText() {
return $this->_pretagtext;
}
public function setPreTagText($value) {
if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
$this->_pretagtext = TPropertyValue::ensureString($value);
}
public function getPreContentsText() {
return $this->_precontentstext;
}
public function setPreContentsText($value) {
if(!$this->_control->getIsSkinApplied())
$this->_precontentstext = TPropertyValue::ensureString($value);
}
public function getPostContentsText() {
return $this->_postcontentstext;
}
public function setPostContentsText($value) {
if(!$this->_control->getIsSkinApplied())
$this->_postcontentstext = TPropertyValue::ensureString($value);
}
public function getPostTagText() {
return $this->_posttagtext;
}
public function setPostTagText($value) {
if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
$this->_posttagtext = TPropertyValue::ensureString($value);
}
public function getPreTagTemplate() {
return $this->_pretagtemplate;
}
public function setPreTagTemplate($value) {
if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
$this->_pretagtemplate = $value;
}
public function getPreContentsTemplate() {
return $this->_precontentstemplate;
}
public function setPreContentsTemplate($value) {
if(!$this->_control->getIsSkinApplied())
$this->_precontentstemplate = $value;
}
public function getPostContentsTemplate() {
return $this->_postcontentstemplate;
}
public function setPostContentsTemplate($value) {
if(!$this->_control->getIsSkinApplied())
$this->_postcontentstemplate = $value;
}
public function getPostTagTemplate() {
return $this->_posttagtemplate;
}
public function setPostTagTemplate($value) {
if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
$this->_posttagtemplate = $value;
}
public function instantiate($outercontrol = null) {
if($this->getPreTagTemplate() || $this->getPreContentsTemplate() ||
$this->getPostContentsTemplate() || $this->getPostTagTemplate()) {
$this->_outercontrol = $outercontrol;
if($this->getUseState())
$this->ensureTemplateDecoration();
else
$this->_control->getPage()->onSaveStateComplete[] = array($this, 'ensureTemplateDecoration');
}
}
public function ensureTemplateDecoration($sender=null, $param=null) {
$control = $this->_control;
$outercontrol = $this->_outercontrol;
if($outercontrol === null)
$outercontrol = $control;
if($this->_addedTemplateDecoration)
return $this->_addedTemplateDecoration;
$this->_addedTemplateDecoration = true;
if($this->getPreContentsTemplate())
{
$precontents = Prado::createComponent('TCompositeControl');
$this->getPreContentsTemplate()->instantiateIn($precontents);
$control->getControls()->insertAt(0, $precontents);
}
if($this->getPostContentsTemplate())
{
$postcontents = Prado::createComponent('TCompositeControl');
$this->getPostContentsTemplate()->instantiateIn($postcontents);
$control->getControls()->add($postcontents);
}
if(!$outercontrol->getParent())
return $this->_addedTemplateDecoration;
if($this->getPreTagTemplate())
{
$pretag = Prado::createComponent('TCompositeControl');
$this->getPreTagTemplate()->instantiateIn($pretag);
$outercontrol->getParent()->getControls()->insertBefore($outercontrol, $pretag);
}
if($this->getPostTagTemplate())
{
$posttag = Prado::createComponent('TCompositeControl');
$this->getPostTagTemplate()->instantiateIn($posttag);
$outercontrol->getParent()->getControls()->insertAfter($outercontrol, $posttag);
}
return true;
}
public function renderPreTagText($writer) {
$writer->write($this->getPreTagText());
}
public function renderPreContentsText($writer) {
$writer->write($this->getPreContentsText());
}
public function renderPostContentsText($writer) {
$writer->write($this->getPostContentsText());
}
public function renderPostTagText($writer) {
$writer->write($this->getPostTagText());
}
}
class TWebControl extends TControl implements IStyleable
{
private $_ensureid=false;
protected $_decorator;
public function setEnsureId($value)
{
$this->_ensureid |= TPropertyValue::ensureBoolean($value);
}
public function getEnsureId()
{
return $this->_ensureid;
}
public function getDecorator($create=true)
{
if($create && !$this->_decorator)
$this->_decorator = Prado::createComponent('TWebControlDecorator', $this);
return $this->_decorator;
}
public function copyBaseAttributes(TWebControl $control)
{
$this->setAccessKey($control->getAccessKey());
$this->setToolTip($control->getToolTip());
$this->setTabIndex($control->getTabIndex());
if(!$control->getEnabled())
$this->setEnabled(false);
if($control->getHasAttributes())
$this->getAttributes()->copyFrom($control->getAttributes());
}
public function getAccessKey()
{
return $this->getViewState('AccessKey','');
}
public function setAccessKey($value)
{
if(strlen($value)>1)
throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
$this->setViewState('AccessKey',$value,'');
}
public function getBackColor()
{
if($style=$this->getViewState('Style',null))
return $style->getBackColor();
else
return '';
}
public function setBackColor($value)
{
$this->getStyle()->setBackColor($value);
}
public function getBorderColor()
{
if($style=$this->getViewState('Style',null))
return $style->getBorderColor();
else
return '';
}
public function setBorderColor($value)
{
$this->getStyle()->setBorderColor($value);
}
public function getBorderStyle()
{
if($style=$this->getViewState('Style',null))
return $style->getBorderStyle();
else
return '';
}
public function setBorderStyle($value)
{
$this->getStyle()->setBorderStyle($value);
}
public function getBorderWidth()
{
if($style=$this->getViewState('Style',null))
return $style->getBorderWidth();
else
return '';
}
public function setBorderWidth($value)
{
$this->getStyle()->setBorderWidth($value);
}
public function getFont()
{
return $this->getStyle()->getFont();
}
public function getForeColor()
{
if($style=$this->getViewState('Style',null))
return $style->getForeColor();
else
return '';
}
public function setForeColor($value)
{
$this->getStyle()->setForeColor($value);
}
public function getHeight()
{
if($style=$this->getViewState('Style',null))
return $style->getHeight();
else
return '';
}
public function setDisplay($value)
{
$this->getStyle()->setDisplayStyle($value);
}
public function getDisplay()
{
return $this->getStyle()->getDisplayStyle();
}
public function setCssClass($value)
{
$this->getStyle()->setCssClass($value);
}
public function getCssClass()
{
if($style=$this->getViewState('Style',null))
return $style->getCssClass();
else
return '';
}
public function setHeight($value)
{
$this->getStyle()->setHeight($value);
}
public function getHasStyle()
{
return $this->getViewState('Style',null)!==null;
}
protected function createStyle()
{
return new TStyle;
}
public function getStyle()
{
if($style=$this->getViewState('Style',null))
return $style;
else
{
$style=$this->createStyle();
$this->setViewState('Style',$style,null);
return $style;
}
}
public function setStyle($value)
{
if(is_string($value))
$this->getStyle()->setCustomStyle($value);
else
throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
}
public function clearStyle()
{
$this->clearViewState('Style');
}
public function getTabIndex()
{
return $this->getViewState('TabIndex',0);
}
public function setTabIndex($value)
{
$this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
}
protected function getTagName()
{
return 'span';
}
public function getToolTip()
{
return $this->getViewState('ToolTip','');
}
public function setToolTip($value)
{
$this->setViewState('ToolTip',$value,'');
}
public function getWidth()
{
if($style=$this->getViewState('Style',null))
return $style->getWidth();
else
return '';
}
public function setWidth($value)
{
$this->getStyle()->setWidth($value);
}
public function onPreRender($param) {
if($decorator = $this->getDecorator(false))
$decorator->instantiate();
parent::onPreRender($param);
}
protected function addAttributesToRender($writer)
{
if($this->getID()!=='' || $this->getEnsureId())
$writer->addAttribute('id',$this->getClientID());
if(($accessKey=$this->getAccessKey())!=='')
$writer->addAttribute('accesskey',$accessKey);
if(!$this->getEnabled())
$writer->addAttribute('disabled','disabled');
if(($tabIndex=$this->getTabIndex())>0)
$writer->addAttribute('tabindex',"$tabIndex");
if(($toolTip=$this->getToolTip())!=='')
$writer->addAttribute('title',$toolTip);
if($style=$this->getViewState('Style',null))
$style->addAttributesToRender($writer);
if($this->getHasAttributes())
{
foreach($this->getAttributes() as $name=>$value)
$writer->addAttribute($name,$value);
}
}
public function render($writer)
{
$this->renderBeginTag($writer);
$this->renderContents($writer);
$this->renderEndTag($writer);
}
public function renderBeginTag($writer)
{
if($decorator = $this->getDecorator(false)) {
$decorator->renderPreTagText($writer);
$this->addAttributesToRender($writer);
$writer->renderBeginTag($this->getTagName());
$decorator->renderPreContentsText($writer);
} else {
$this->addAttributesToRender($writer);
$writer->renderBeginTag($this->getTagName());
}
}
public function renderContents($writer)
{
parent::renderChildren($writer);
}
public function renderEndTag($writer)
{
if($decorator = $this->getDecorator(false)) {
$decorator->renderPostContentsText($writer);
$writer->renderEndTag();
$decorator->renderPostTagText($writer);
} else
$writer->renderEndTag($writer);
}
}
class TCompositeControl extends TControl implements INamingContainer
{
protected function initRecursive($namingContainer=null)
{
$this->ensureChildControls();
parent::initRecursive($namingContainer);
}
}
class TTemplateControl extends TCompositeControl
{
const EXT_TEMPLATE='.tpl';
private static $_template=array();
private $_localTemplate=null;
private $_master=null;
private $_masterClass='';
private $_contents=array();
private $_placeholders=array();
public function getTemplate()
{
if($this->_localTemplate===null)
{
$class=get_class($this);
if(!isset(self::$_template[$class]))
self::$_template[$class]=$this->loadTemplate();
return self::$_template[$class];
}
else
return $this->_localTemplate;
}
public function setTemplate($value)
{
$this->_localTemplate=$value;
}
public function getIsSourceTemplateControl()
{
if(($template=$this->getTemplate())!==null)
return $template->getIsSourceTemplate();
else
return false;
}
public function getTemplateDirectory()
{
if(($template=$this->getTemplate())!==null)
return $template->getContextPath();
else
return '';
}
protected function loadTemplate()
{
$template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
return $template;
}
public function createChildControls()
{
if($tpl=$this->getTemplate())
{
foreach($tpl->getDirective() as $name=>$value)
{
if(is_string($value))
$this->setSubProperty($name,$value);
else
throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
}
$tpl->instantiateIn($this);
}
}
public function registerContent($id,TContent $object)
{
if(isset($this->_contents[$id]))
throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
else
$this->_contents[$id]=$object;
}
public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
{
if(isset($this->_placeholders[$id]))
throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
else
$this->_placeholders[$id]=$object;
}
public function getMasterClass()
{
return $this->_masterClass;
}
public function setMasterClass($value)
{
$this->_masterClass=$value;
}
public function getMaster()
{
return $this->_master;
}
public function injectContent($id,$content)
{
if(isset($this->_placeholders[$id]))
{
$placeholder=$this->_placeholders[$id];
$controls=$placeholder->getParent()->getControls();
$loc=$controls->remove($placeholder);
$controls->insertAt($loc,$content);
}
else
throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
}
protected function initRecursive($namingContainer=null)
{
$this->ensureChildControls();
if($this->_masterClass!=='')
{
$master=Prado::createComponent($this->_masterClass);
if(!($master instanceof TTemplateControl))
throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
$this->_master=$master;
$this->getControls()->clear();
$this->getControls()->add($master);
$master->ensureChildControls();
foreach($this->_contents as $id=>$content)
$master->injectContent($id,$content);
}
else if(!empty($this->_contents))
throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
parent::initRecursive($namingContainer);
}
}
class TForm extends TControl
{
public function onInit($param)
{
parent::onInit($param);
$this->getPage()->setForm($this);
}
protected function addAttributesToRender($writer)
{
$writer->addAttribute('id',$this->getClientID());
$writer->addAttribute('method',$this->getMethod());
$uri=$this->getRequest()->getRequestURI();
$writer->addAttribute('action',str_replace('&','&',str_replace('&','&',$uri)));
if(($enctype=$this->getEnctype())!=='')
$writer->addAttribute('enctype',$enctype);
$attributes=$this->getAttributes();
$attributes->remove('action');
$writer->addAttributes($attributes);
if(($butt=$this->getDefaultButton())!=='')
{
if(($button=$this->findControl($butt))!==null)
$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
else
throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
}
}
public function render($writer)
{
$page=$this->getPage();
$this->addAttributesToRender($writer);
$writer->renderBeginTag('form');
$cs=$page->getClientScript();
if($page->getClientSupportsJavaScript())
{
$cs->renderHiddenFieldsBegin($writer);
$cs->renderScriptFilesBegin($writer);
$cs->renderBeginScripts($writer);
$page->beginFormRender($writer);
$this->renderChildren($writer);
$cs->renderHiddenFieldsEnd($writer);
$page->endFormRender($writer);
$cs->renderScriptFilesEnd($writer);
$cs->renderEndScripts($writer);
}
else
{
$cs->renderHiddenFieldsBegin($writer);
$page->beginFormRender($writer);
$this->renderChildren($writer);
$page->endFormRender($writer);
$cs->renderHiddenFieldsEnd($writer);
}
$writer->renderEndTag();
}
public function getDefaultButton()
{
return $this->getViewState('DefaultButton','');
}
public function setDefaultButton($value)
{
$this->setViewState('DefaultButton',$value,'');
}
public function getMethod()
{
return $this->getViewState('Method','post');
}
public function setMethod($value)
{
$this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
}
public function getEnctype()
{
return $this->getViewState('Enctype','');
}
public function setEnctype($value)
{
$this->setViewState('Enctype',$value,'');
}
public function getName()
{
return $this->getUniqueID();
}
}
class TClientScriptManager extends TApplicationComponent
{
const SCRIPT_PATH='Web/Javascripts/source';
const PACKAGES_FILE='Web/Javascripts/packages.php';
private $_page;
private $_hiddenFields=array();
private $_beginScripts=array();
private $_endScripts=array();
private $_scriptFiles=array();
private $_headScriptFiles=array();
private $_headScripts=array();
private $_styleSheetFiles=array();
private $_styleSheets=array();
private $_registeredPradoScripts=array();
private static $_pradoScripts;
private static $_pradoPackages;
private $_renderedHiddenFields;
private $_renderedScriptFiles=array();
private $_expandedPradoScripts;
public function __construct(TPage $owner)
{
$this->_page=$owner;
}
public function getRequiresHead()
{
return count($this->_styleSheetFiles) || count($this->_styleSheets)
|| count($this->_headScriptFiles) || count($this->_headScripts);
}
public static function getPradoPackages()
{
return self::$_pradoPackages;
}
public static function getPradoScripts()
{
return self::$_pradoScripts;
}
public function registerPradoScript($name)
{
$this->registerPradoScriptInternal($name);
$params=func_get_args();
$this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
}
protected function registerPradoScriptInternal($name)
{
if(!isset($this->_registeredPradoScripts[$name]))
{
if(self::$_pradoScripts === null)
{
$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::PACKAGES_FILE;
list($packages,$deps)= include($packageFile);
self::$_pradoScripts = $deps;
self::$_pradoPackages = $packages;
}
if (isset(self::$_pradoScripts[$name]))
$this->_registeredPradoScripts[$name]=true;
else
throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
if(($packages=array_keys($this->_registeredPradoScripts))!==array())
{
$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
list($path,$baseUrl)=$this->getPackagePathUrl($base);
$packagesUrl=array();
$isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
foreach ($packages as $p)
{
foreach (self::$_pradoScripts[$p] as $dep)
{
foreach (self::$_pradoPackages[$dep] as $script)
if (!isset($this->_expandedPradoScripts[$script]))
{
$this->_expandedPradoScripts[$script] = true;
if($isDebug)
{
if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
$packagesUrl[]=$url;
} else {
if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))
{
if(!is_file($filePath=$path.'/min/'.$script))
{
$dirPath=dirname($filePath);
if(!is_dir($dirPath))
mkdir($dirPath, PRADO_CHMOD, true);
file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script)));
chmod($filePath, PRADO_CHMOD);
}
$packagesUrl[]=$url;
}
}
}
}
}
foreach($packagesUrl as $url)
$this->registerScriptFile($url,$url);
}
}
}
public function getPradoScriptAssetUrl()
{
$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
$assets = Prado::getApplication()->getAssetManager();
return $assets->getPublishedUrl($base);
}
public function getScriptUrls()
{
$scripts = array_values($this->_headScriptFiles);
$scripts = array_merge($scripts, array_values($this->_scriptFiles));
$scripts = array_unique($scripts);
return $scripts;
}
protected function getPackagePathUrl($base)
{
$assets = Prado::getApplication()->getAssetManager();
if(strpos($base, $assets->getBaseUrl())===false)
{
if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
$base = $dir;
}
return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
}
else
{
return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
}
}
public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
{
$options = !is_array($options) ? array() : $options;
$class = new ReflectionClass($callbackHandler);
$clientSide = $callbackHandler->getActiveControl()->getClientSide();
$options = array_merge($options, $clientSide->getOptions()->toArray());
$optionString = TJavaScript::encode($options);
$this->registerPradoScriptInternal('ajax');
$id = $callbackHandler->getUniqueID();
return "new Prado.CallbackRequest('{$id}',{$optionString})";
}
public function registerCallbackControl($class, $options)
{
$optionString=TJavaScript::encode($options);
$code="new {$class}({$optionString});";
$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
$this->registerPradoScriptInternal('ajax');
$params=func_get_args();
$this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
}
public function registerPostBackControl($class,$options)
{
if($class === null) {
return;
}
if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
$options['FormID']=$form->getClientID();
$optionString=TJavaScript::encode($options);
$code="new {$class}({$optionString});";
$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
$this->_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['ID'] = TControl::convertUniqueIdToClientId($panelID);
$options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
$options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
$options['EventTarget'] = $buttonID;
$options['Event'] = 'click';
return $options;
}
public function registerFocusControl($target)
{
$this->registerPradoScriptInternal('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 getStyleSheetUrls()
{
$stylesheets = array_values(array_merge($this->_styleSheetFiles, $this->_styleSheets));
foreach(Prado::getApplication()->getAssetManager()->getPublished() as $path=>$url)
if (substr($url,strlen($url)-4)=='.css')
$stylesheets[] = $url;
$stylesheets = array_unique($stylesheets);
return $stylesheets;
}
public function registerHeadScriptFile($key,$url)
{
$this->checkIfNotInRender();
$this->_headScriptFiles[$key]=$url;
$params=func_get_args();
$this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
}
public function registerHeadScript($key,$script)
{
$this->checkIfNotInRender();
$this->_headScripts[$key]=$script;
$params=func_get_args();
$this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
}
public function registerScriptFile($key, $url)
{
$this->_scriptFiles[$key]=$url;
$params=func_get_args();
$this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
}
public function registerBeginScript($key,$script)
{
$this->checkIfNotInRender();
$this->_beginScripts[$key]=$script;
$params=func_get_args();
$this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
}
public function registerEndScript($key,$script)
{
$this->_endScripts[$key]=$script;
$params=func_get_args();
$this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
}
public function registerHiddenField($name,$value)
{
$this->_hiddenFields[$name]=$value;
$params=func_get_args();
$this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
}
public function isStyleSheetFileRegistered($key)
{
return isset($this->_styleSheetFiles[$key]);
}
public function isStyleSheetRegistered($key)
{
return isset($this->_styleSheets[$key]);
}
public function isHeadScriptFileRegistered($key)
{
return isset($this->_headScriptFiles[$key]);
}
public function isHeadScriptRegistered($key)
{
return isset($this->_headScripts[$key]);
}
public function isScriptFileRegistered($key)
{
return isset($this->_scriptFiles[$key]);
}
public function isBeginScriptRegistered($key)
{
return isset($this->_beginScripts[$key]);
}
public function isEndScriptRegistered($key)
{
return isset($this->_endScripts[$key]);
}
public function hasEndScripts()
{
return count($this->_endScripts) > 0;
}
public function hasBeginScripts()
{
return count($this->_beginScripts) > 0;
}
public function isHiddenFieldRegistered($key)
{
return isset($this->_hiddenFields[$key]);
}
public function renderStyleSheetFiles($writer)
{
$str='';
foreach($this->_styleSheetFiles as $url)
{
if(is_array($url))
$str.=" \n";
else
$str.=" \n";
}
$writer->write($str);
}
public function renderStyleSheets($writer)
{
if(count($this->_styleSheets))
$writer->write("\n");
}
public function renderHeadScriptFiles($writer)
{
$this->renderScriptFiles($writer,$this->_headScriptFiles);
}
public function renderHeadScripts($writer)
{
$writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
}
public function renderScriptFilesBegin($writer)
{
$this->renderAllPendingScriptFiles($writer);
}
public function renderScriptFilesEnd($writer)
{
$this->renderAllPendingScriptFiles($writer);
}
public function markScriptFileAsRendered($url)
{
$this->_renderedScriptFiles[$url] = $url;
$params=func_get_args();
$this->_page->registerCachingAction('Page.ClientScript','markScriptFileAsRendered',$params);
}
protected function renderScriptFiles($writer, Array $scripts)
{
foreach($scripts as $script)
{
$writer->write(TJavaScript::renderScriptFile($script));
$this->markScriptFileAsRendered($script);
}
}
protected function getRenderedScriptFiles()
{
return $this->_renderedScriptFiles;
}
public function renderAllPendingScriptFiles($writer)
{
if(!empty($this->_scriptFiles))
{
$addedScripts = array_diff($this->_scriptFiles,$this->getRenderedScriptFiles());
$this->renderScriptFiles($writer,$addedScripts);
}
}
public function renderBeginScripts($writer)
{
$writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
}
public function renderEndScripts($writer)
{
$writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
}
public function renderHiddenFieldsBegin($writer)
{
$this->renderHiddenFieldsInt($writer,true);
}
public function renderHiddenFieldsEnd($writer)
{
$this->renderHiddenFieldsInt($writer,false);
}
public function flushScriptFiles($writer, $control=null)
{
$this->_page->ensureRenderInForm($control);
$this->renderAllPendingScriptFiles($writer);
}
protected function renderHiddenFieldsInt($writer, $initial)
{
if ($initial) $this->_renderedHiddenFields = array();
$str='';
foreach($this->_hiddenFields as $name=>$value)
{
if (in_array($name,$this->_renderedHiddenFields)) continue;
$id=strtr($name,':','_');
if(is_array($value))
{
foreach($value as $v)
$str.=' \n";
}
else
{
$str.=' \n";
}
$this->_renderedHiddenFields[] = $name;
}
if($str!=='')
$writer->write("\n".$str."
\n");
}
public function getHiddenFields()
{
return $this->_hiddenFields;
}
protected function checkIfNotInRender()
{
if ($form = $this->_page->InFormRender)
throw new Exception('Operation invalid when page is already rendering');
}
}
abstract class TClientSideOptions extends TComponent
{
private $_options;
public function __construct()
{
$this->_options = Prado::createComponent('System.Collections.TMap');
}
protected function setFunction($name, $code)
{
if(!TJavaScript::isJsLiteral($code))
$code = TJavaScript::quoteJsLiteral($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;
protected $_postData;
protected $_restPostData;
protected $_controlsPostDataChanged=array();
protected $_controlsRequiringPostData=array();
protected $_controlsRegisteredForPostData=array();
private $_postBackEventTarget;
private $_postBackEventParameter;
protected $_formRendered=false;
protected $_inFormRender=false;
private $_focus;
private $_pagePath='';
private $_enableStateValidation=true;
private $_enableStateEncryption=false;
private $_enableStateCompression=true;
private $_statePersisterClass='System.Web.UI.TPageStatePersister';
private $_statePersister;
private $_cachingStack;
private $_clientState='';
protected $_postDataLoaders=array();
protected $_isLoadingPostData=false;
private $_enableJavaScript=true;
private $_writer;
public function __construct()
{
$this->setPage($this);
}
public function run($writer)
{
$this->_writer = $writer;
$this->determinePostBackMode();
if($this->getIsPostBack())
{
if($this->getIsCallback())
$this->processCallbackRequest($writer);
else
$this->processPostBackRequest($writer);
}
else
$this->processNormalRequest($writer);
$this->_writer = null;
}
protected function processNormalRequest($writer)
{
$this->onPreInit(null);
$this->initRecursive();
$this->onInitComplete(null);
$this->onPreLoad(null);
$this->loadRecursive();
$this->onLoadComplete(null);
$this->preRenderRecursive();
$this->onPreRenderComplete(null);
$this->savePageState();
$this->onSaveStateComplete(null);
$this->renderControl($writer);
$this->unloadRecursive();
}
protected function processPostBackRequest($writer)
{
$this->onPreInit(null);
$this->initRecursive();
$this->onInitComplete(null);
$this->_restPostData=new TMap;
$this->loadPageState();
$this->processPostData($this->_postData,true);
$this->onPreLoad(null);
$this->loadRecursive();
$this->processPostData($this->_restPostData,false);
$this->raiseChangedEvents();
$this->raisePostBackEvent();
$this->onLoadComplete(null);
$this->preRenderRecursive();
$this->onPreRenderComplete(null);
$this->savePageState();
$this->onSaveStateComplete(null);
$this->renderControl($writer);
$this->unloadRecursive();
}
protected static function decodeUTF8($data, $enc)
{
if(is_array($data))
{
foreach($data as $k=>$v)
$data[$k]=self::decodeUTF8($v, $enc);
return $data;
} elseif(is_string($data)) {
return iconv('UTF-8',$enc.'//IGNORE',$data);
} else {
return $data;
}
}
protected function processCallbackRequest($writer)
{
Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
$this->setAdapter(new TActivePageAdapter($this));
if (($g=$this->getApplication()->getGlobalization(false))!==null &&
strtoupper($enc=$g->getCharset())!='UTF-8')
foreach ($this->_postData as $k=>$v)
$this->_postData[$k]=self::decodeUTF8($v, $enc);
$this->onPreInit(null);
$this->initRecursive();
$this->onInitComplete(null);
$this->_restPostData=new TMap;
$this->loadPageState();
$this->processPostData($this->_postData,true);
$this->onPreLoad(null);
$this->loadRecursive();
$this->processPostData($this->_restPostData,false);
$this->raiseChangedEvents();
$this->getAdapter()->processCallbackEvent($writer);
$this->onLoadComplete(null);
$this->preRenderRecursive();
$this->onPreRenderComplete(null);
$this->savePageState();
$this->onSaveStateComplete(null);
$this->getAdapter()->renderCallbackResponse($writer);
$this->unloadRecursive();
}
public function getCallbackClient()
{
if($this->getAdapter() !== null)
return $this->getAdapter()->getCallbackClientHandler();
else
return new TCallbackClientScript();
}
public function setCallbackClient($client)
{
$this->getAdapter()->setCallbackClientHandler($client);
}
public function getCallbackEventTarget()
{
return $this->getAdapter()->getCallbackEventTarget();
}
public function setCallbackEventTarget(TControl $control)
{
$this->getAdapter()->setCallbackEventTarget($control);
}
public function getCallbackEventParameter()
{
return $this->getAdapter()->getCallbackEventParameter();
}
public function setCallbackEventParameter($value)
{
$this->getAdapter()->setCallbackEventParameter($value);
}
public function 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(empty($validationGroup) === true)
return $this->_validators;
else
{
$list=new TList;
foreach($this->_validators as $validator)
if($validator->getValidationGroup()===$validationGroup)
$list->add($validator);
return $list;
}
}
public function validate($validationGroup=null)
{
$this->_validated=true;
if($this->_validators && $this->_validators->getCount())
{
if($validationGroup===null)
{
foreach($this->_validators as $validator)
$validator->validate();
}
else
{
foreach($this->_validators as $validator)
{
if($validator->getValidationGroup()===$validationGroup)
$validator->validate();
}
}
}
}
public function getIsValid()
{
if($this->_validated)
{
if($this->_validators && $this->_validators->getCount())
{
foreach($this->_validators as $validator)
if(!$validator->getIsValid())
return false;
}
return true;
}
else
throw new TInvalidOperationException('page_isvalid_unknown');
}
public function getTheme()
{
if(is_string($this->_theme))
$this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
return $this->_theme;
}
public function setTheme($value)
{
$this->_theme=empty($value)?null:$value;
}
public function getStyleSheetTheme()
{
if(is_string($this->_styleSheet))
$this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
return $this->_styleSheet;
}
public function setStyleSheetTheme($value)
{
$this->_styleSheet=empty($value)?null:$value;
}
public function applyControlSkin($control)
{
if(($theme=$this->getTheme())!==null)
$theme->applySkin($control);
}
public function applyControlStyleSheet($control)
{
if(($theme=$this->getStyleSheetTheme())!==null)
$theme->applySkin($control);
}
public function getClientScript()
{
if(!$this->_clientScript) {
$className = $classPath = $this->getService()->getClientScriptManagerClass();
Prado::using($className);
if(($pos=strrpos($className,'.'))!==false)
$className=substr($className,$pos+1);
if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
$this->_clientScript=new $className($this);
}
return $this->_clientScript;
}
public function onPreInit($param)
{
$this->raiseEvent('OnPreInit',$this,$param);
}
public function onInitComplete($param)
{
$this->raiseEvent('OnInitComplete',$this,$param);
}
public function onPreLoad($param)
{
$this->raiseEvent('OnPreLoad',$this,$param);
}
public function onLoadComplete($param)
{
$this->raiseEvent('OnLoadComplete',$this,$param);
}
public function onPreRenderComplete($param)
{
$this->raiseEvent('OnPreRenderComplete',$this,$param);
$cs=$this->getClientScript();
$theme=$this->getTheme();
if($theme instanceof ITheme)
{
foreach($theme->getStyleSheetFiles() as $url)
$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
foreach($theme->getJavaScriptFiles() as $url)
$cs->registerHeadScriptFile($url,$url);
}
$styleSheet=$this->getStyleSheetTheme();
if($styleSheet instanceof ITheme)
{
foreach($styleSheet->getStyleSheetFiles() as $url)
$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
foreach($styleSheet->getJavaScriptFiles() as $url)
$cs->registerHeadScriptFile($url,$url);
}
if($cs->getRequiresHead() && $this->getHead()===null)
throw new TConfigurationException('page_head_required');
}
private function getCssMediaType($url)
{
$segs=explode('.',basename($url));
if(isset($segs[2]))
return $segs[count($segs)-2];
else
return '';
}
public function onSaveStateComplete($param)
{
$this->raiseEvent('OnSaveStateComplete',$this,$param);
}
private function determinePostBackMode()
{
$postData=$this->getRequest();
if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
$this->_postData=$postData;
}
public function getIsPostBack()
{
return $this->_postData!==null;
}
public function getIsCallback()
{
return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
}
public function saveState()
{
parent::saveState();
$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
}
public function loadState()
{
parent::loadState();
$this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
}
protected function loadPageState()
{
$state=$this->getStatePersister()->load();
$this->loadStateRecursive($state,$this->getEnableViewState());
}
protected function savePageState()
{
$state=&$this->saveStateRecursive($this->getEnableViewState());
$this->getStatePersister()->save($state);
}
protected function isSystemPostField($field)
{
return isset(self::$_systemPostFields[$field]);
}
public function registerRequiresPostData($control)
{
$id=is_string($control)?$control:$control->getUniqueID();
$this->_controlsRegisteredForPostData[$id]=true;
$this->registerPostDataLoader($id);
$params=func_get_args();
foreach($this->getCachingStack() as $item)
$item->registerAction('Page','registerRequiresPostData',array($id));
}
public function getPostBackEventTarget()
{
if($this->_postBackEventTarget===null && $this->_postData!==null)
{
$eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
if(!empty($eventTarget))
$this->_postBackEventTarget=$this->findControl($eventTarget);
}
return $this->_postBackEventTarget;
}
public function setPostBackEventTarget(TControl $control)
{
$this->_postBackEventTarget=$control;
}
public function getPostBackEventParameter()
{
if($this->_postBackEventParameter===null && $this->_postData!==null)
{
if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
$this->_postBackEventParameter='';
}
return $this->_postBackEventParameter;
}
public function setPostBackEventParameter($value)
{
$this->_postBackEventParameter=$value;
}
protected function processPostData($postData,$beforeLoad)
{
$this->_isLoadingPostData=true;
if($beforeLoad)
$this->_restPostData=new TMap;
foreach($postData as $key=>$value)
{
if($this->isSystemPostField($key))
continue;
else if($control=$this->findControl($key))
{
if($control instanceof IPostBackDataHandler)
{
if($control->loadPostData($key,$postData))
$this->_controlsPostDataChanged[]=$control;
}
else if($control instanceof IPostBackEventHandler &&
empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
{
$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); }
unset($this->_controlsRequiringPostData[$key]);
}
else if($beforeLoad)
$this->_restPostData->add($key,$value);
}
foreach($this->_controlsRequiringPostData as $key=>$value)
{
if($control=$this->findControl($key))
{
if($control instanceof IPostBackDataHandler)
{
if($control->loadPostData($key,$this->_postData))
$this->_controlsPostDataChanged[]=$control;
}
else
throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
unset($this->_controlsRequiringPostData[$key]);
}
}
$this->_isLoadingPostData=false;
}
public function getIsLoadingPostData()
{
return $this->_isLoadingPostData;
}
protected function raiseChangedEvents()
{
foreach($this->_controlsPostDataChanged as $control)
$control->raisePostDataChangedEvent();
}
protected function raisePostBackEvent()
{
if(($postBackHandler=$this->getPostBackEventTarget())===null)
$this->validate();
else if($postBackHandler instanceof IPostBackEventHandler)
$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
}
public function getInFormRender()
{
return $this->_inFormRender;
}
public function ensureRenderInForm($control)
{
if(!$this->getIsCallback() && !$this->_inFormRender)
throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
}
public function beginFormRender($writer)
{
if($this->_formRendered)
throw new TConfigurationException('page_form_duplicated');
$this->_formRendered=true;
$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
$this->_inFormRender=true;
}
public function endFormRender($writer)
{
if($this->_focus)
{
if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
$focus=$this->_focus->getClientID();
else
$focus=$this->_focus;
$this->getClientScript()->registerFocusControl($focus);
}
else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
$this->getClientScript()->registerFocusControl($lastFocus);
$this->_inFormRender=false;
}
public function setFocus($value)
{
$this->_focus=$value;
}
public function getClientSupportsJavaScript()
{
return $this->_enableJavaScript;
}
public function setClientSupportsJavaScript($value)
{
$this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
}
public function getHead()
{
return $this->_head;
}
public function setHead(THead $value)
{
if($this->_head)
throw new TInvalidOperationException('page_head_duplicated');
$this->_head=$value;
if($this->_title!==null)
{
$this->_head->setTitle($this->_title);
$this->_title=null;
}
}
public function getTitle()
{
if($this->_head)
return $this->_head->getTitle();
else
return $this->_title===null ? '' : $this->_title;
}
public function setTitle($value)
{
if($this->_head)
$this->_head->setTitle($value);
else
$this->_title=$value;
}
public function getClientState()
{
return $this->_clientState;
}
public function setClientState($state)
{
$this->_clientState=$state;
}
public function getRequestClientState()
{
return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
}
public function getStatePersisterClass()
{
return $this->_statePersisterClass;
}
public function setStatePersisterClass($value)
{
$this->_statePersisterClass=$value;
}
public function getStatePersister()
{
if($this->_statePersister===null)
{
$this->_statePersister=Prado::createComponent($this->_statePersisterClass);
if(!($this->_statePersister instanceof IPageStatePersister))
throw new TInvalidDataTypeException('page_statepersister_invalid');
$this->_statePersister->setPage($this);
}
return $this->_statePersister;
}
public function getEnableStateValidation()
{
return $this->_enableStateValidation;
}
public function setEnableStateValidation($value)
{
$this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
}
public function getEnableStateEncryption()
{
return $this->_enableStateEncryption;
}
public function setEnableStateEncryption($value)
{
$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
}
public function getEnableStateCompression()
{
return $this->_enableStateCompression;
}
public function setEnableStateCompression($value)
{
$this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
}
public function getPagePath()
{
return $this->_pagePath;
}
public function setPagePath($value)
{
$this->_pagePath=$value;
}
public function registerCachingAction($context,$funcName,$funcParams)
{
if($this->_cachingStack)
{
foreach($this->_cachingStack as $cache)
$cache->registerAction($context,$funcName,$funcParams);
}
}
public function getCachingStack()
{
if(!$this->_cachingStack)
$this->_cachingStack=new TStack;
return $this->_cachingStack;
}
public function flushWriter()
{
if ($this->_writer)
$this->Response->write($this->_writer->flush());
}
}
interface IPageStatePersister
{
public function getPage();
public function setPage(TPage $page);
public function save($state);
public function load();
}
class TPageStateFormatter
{
public static function serialize($page,$data)
{
$sm=$page->getApplication()->getSecurityManager();
if($page->getEnableStateValidation())
$str=$sm->hashData(Prado::serialize($data));
else
$str=Prado::serialize($data);
if($page->getEnableStateCompression() && extension_loaded('zlib'))
$str=gzcompress($str);
if($page->getEnableStateEncryption())
$str=$sm->encrypt($str);
return base64_encode($str);
}
public static function unserialize($page,$data)
{
$str=base64_decode($data);
if($str==='')
return null;
if($str!==false)
{
$sm=$page->getApplication()->getSecurityManager();
if($page->getEnableStateEncryption())
$str=$sm->decrypt($str);
if($page->getEnableStateCompression() && extension_loaded('zlib'))
$str=@gzuncompress($str);
if($page->getEnableStateValidation())
{
if(($str=$sm->validateData($str))!==false)
return Prado::unserialize($str);
}
else
return Prado::unserialize($str);
}
return null;
}
}
class TOutputCache extends TControl implements INamingContainer
{
const CACHE_ID_PREFIX='prado:outputcache';
private $_cacheModuleID='';
private $_dataCached=false;
private $_cacheAvailable=false;
private $_cacheChecked=false;
private $_cacheKey=null;
private $_duration=60;
private $_cache=null;
private $_contents;
private $_state;
private $_actions=array();
private $_varyByParam='';
private $_keyPrefix='';
private $_varyBySession=false;
private $_cachePostBack=false;
private $_cacheTime=0;
public function getAllowChildControls()
{
$this->determineCacheability();
return !$this->_dataCached;
}
private function determineCacheability()
{
if(!$this->_cacheChecked)
{
$this->_cacheChecked=true;
if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
{
if($this->_cacheModuleID!=='')
{
$this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
if(!($this->_cache instanceof ICache))
throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
}
else
$this->_cache=$this->getApplication()->getCache();
if($this->_cache!==null)
{
$this->_cacheAvailable=true;
$data=$this->_cache->get($this->getCacheKey());
if(is_array($data))
{
$param=new TOutputCacheCheckDependencyEventParameter;
$param->setCacheTime(isset($data[3])?$data[3]:0);
$this->onCheckDependency($param);
$this->_dataCached=$param->getIsValid();
}
else
$this->_dataCached=false;
if($this->_dataCached)
list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
}
}
}
}
protected function initRecursive($namingContainer=null)
{
if($this->_cacheAvailable && !$this->_dataCached)
{
$stack=$this->getPage()->getCachingStack();
$stack->push($this);
parent::initRecursive($namingContainer);
$stack->pop();
}
else
parent::initRecursive($namingContainer);
}
protected function loadRecursive()
{
if($this->_cacheAvailable && !$this->_dataCached)
{
$stack=$this->getPage()->getCachingStack();
$stack->push($this);
parent::loadRecursive();
$stack->pop();
}
else
{
if($this->_dataCached)
$this->performActions();
parent::loadRecursive();
}
}
private function performActions()
{
$page=$this->getPage();
$cs=$page->getClientScript();
foreach($this->_actions as $action)
{
if($action[0]==='Page.ClientScript')
call_user_func_array(array($cs,$action[1]),$action[2]);
else if($action[0]==='Page')
call_user_func_array(array($page,$action[1]),$action[2]);
else
call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
}
}
protected function preRenderRecursive()
{
if($this->_cacheAvailable && !$this->_dataCached)
{
$stack=$this->getPage()->getCachingStack();
$stack->push($this);
parent::preRenderRecursive();
$stack->pop();
}
else
parent::preRenderRecursive();
}
protected function loadStateRecursive(&$state,$needViewState=true)
{
$st=unserialize($state);
parent::loadStateRecursive($st,$needViewState);
}
protected function &saveStateRecursive($needViewState=true)
{
if($this->_dataCached)
return $this->_state;
else
{
$st=parent::saveStateRecursive($needViewState);
$this->_state=serialize($st);
return $this->_state;
}
}
public function registerAction($context,$funcName,$funcParams)
{
$this->_actions[]=array($context,$funcName,$funcParams);
}
public function getCacheKey()
{
if($this->_cacheKey===null)
$this->_cacheKey=$this->calculateCacheKey();
return $this->_cacheKey;
}
protected function calculateCacheKey()
{
$key=$this->getBaseCacheKey();
if($this->_varyBySession)
$key.=$this->getSession()->getSessionID();
if($this->_varyByParam!=='')
{
$params=array();
$request=$this->getRequest();
foreach(explode(',',$this->_varyByParam) as $name)
{
$name=trim($name);
$params[$name]=$request->itemAt($name);
}
$key.=serialize($params);
}
$param=new TOutputCacheCalculateKeyEventParameter;
$this->onCalculateKey($param);
$key.=$param->getCacheKey();
return $key;
}
protected function getBaseCacheKey()
{
return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
}
public function getCacheModuleID()
{
return $this->_cacheModuleID;
}
public function setCacheModuleID($value)
{
$this->_cacheModuleID=$value;
}
public function setCacheKeyPrefix($value)
{
$this->_keyPrefix=$value;
}
public function getCacheTime()
{
return $this->_cacheTime;
}
protected function getCacheDependency()
{
return null;
}
public function getContentCached()
{
return $this->_dataCached;
}
public function getDuration()
{
return $this->_duration;
}
public function setDuration($value)
{
if(($value=TPropertyValue::ensureInteger($value))<0)
throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
$this->_duration=$value;
}
public function getVaryByParam()
{
return $this->_varyByParam;
}
public function setVaryByParam($value)
{
$this->_varyByParam=trim($value);
}
public function getVaryBySession()
{
return $this->_varyBySession;
}
public function setVaryBySession($value)
{
$this->_varyBySession=TPropertyValue::ensureBoolean($value);
}
public function getCachingPostBack()
{
return $this->_cachePostBack;
}
public function setCachingPostBack($value)
{
$this->_cachePostBack=TPropertyValue::ensureBoolean($value);
}
public function onCheckDependency($param)
{
$this->raiseEvent('OnCheckDependency',$this,$param);
}
public function onCalculateKey($param)
{
$this->raiseEvent('OnCalculateKey',$this,$param);
}
public function render($writer)
{
if($this->_dataCached)
$writer->write($this->_contents);
else if($this->_cacheAvailable)
{
$textwriter = new TTextWriter();
$multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
$htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
$stack=$this->getPage()->getCachingStack();
$stack->push($this);
parent::render($htmlWriter);
$stack->pop();
$content=$textwriter->flush();
$data=array($content,$this->_state,$this->_actions,time());
$this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
}
else
parent::render($writer);
}
}
class TOutputCacheCheckDependencyEventParameter extends TEventParameter
{
private $_isValid=true;
private $_cacheTime=0;
public function getIsValid()
{
return $this->_isValid;
}
public function setIsValid($value)
{
$this->_isValid=TPropertyValue::ensureBoolean($value);
}
public function getCacheTime()
{
return $this->_cacheTime;
}
public function setCacheTime($value)
{
$this->_cacheTime=TPropertyValue::ensureInteger($value);
}
}
class TOutputCacheCalculateKeyEventParameter extends TEventParameter
{
private $_cacheKey='';
public function getCacheKey()
{
return $this->_cacheKey;
}
public function setCacheKey($value)
{
$this->_cacheKey=TPropertyValue::ensureString($value);
}
}
class TOutputCacheTextWriterMulti extends TTextWriter
{
protected $_writers;
public function __construct(Array $writers)
{
$this->_writers = $writers;
}
public function write($s)
{
foreach($this->_writers as $writer)
$writer->write($s);
}
public function flush()
{
foreach($this->_writers as $writer)
$s = $writer->flush();
return $s;
}
}
class TTemplateManager extends TModule
{
const TEMPLATE_FILE_EXT='.tpl';
const TEMPLATE_CACHE_PREFIX='prado:template:';
public function init($config)
{
$this->getService()->setTemplateManager($this);
}
public function getTemplateByClassName($className)
{
$class=new ReflectionClass($className);
$tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
return $this->getTemplateByFileName($tplFile);
}
public function getTemplateByFileName($fileName)
{
if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
{
if(($cache=$this->getApplication()->getCache())===null)
return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
else
{
$array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
if(is_array($array))
{
list($template,$timestamps)=$array;
if($this->getApplication()->getMode()===TApplicationMode::Performance)
return $template;
$cacheValid=true;
foreach($timestamps as $tplFile=>$timestamp)
{
if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
{
$cacheValid=false;
break;
}
}
if($cacheValid)
return $template;
}
$template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
$includedFiles=$template->getIncludedFiles();
$timestamps=array();
$timestamps[$fileName]=filemtime($fileName);
foreach($includedFiles as $includedFile)
$timestamps[$includedFile]=filemtime($includedFile);
$cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
return $template;
}
}
else
return null;
}
protected function getLocalizedTemplate($filename)
{
if(($app=$this->getApplication()->getGlobalization(false))===null)
return is_file($filename)?$filename:null;
foreach($app->getLocalizedResource($filename) as $file)
{
if(($file=realpath($file))!==false && is_file($file))
return $file;
}
return null;
}
}
class TTemplate extends TApplicationComponent implements ITemplate
{
const REGEX_RULES='/||<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|)*)\s*\/>/msS';
const CONFIG_DATABIND=0;
const CONFIG_EXPRESSION=1;
const CONFIG_ASSET=2;
const CONFIG_PARAMETER=3;
const CONFIG_LOCALIZATION=4;
const CONFIG_TEMPLATE=5;
private $_tpl=array();
private $_directive=array();
private $_contextPath;
private $_tplFile=null;
private $_startingLine=0;
private $_content;
private $_sourceTemplate=true;
private $_hashCode='';
private $_tplControl=null;
private $_includedFiles=array();
private $_includeAtLine=array();
private $_includeLines=array();
public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
{
$this->_sourceTemplate=$sourceTemplate;
$this->_contextPath=$contextPath;
$this->_tplFile=$tplFile;
$this->_startingLine=$startingLine;
$this->_content=$template;
$this->_hashCode=md5($template);
$this->parse($template);
$this->_content=null; }
public function getTemplateFile()
{
return $this->_tplFile;
}
public function getIsSourceTemplate()
{
return $this->_sourceTemplate;
}
public function getContextPath()
{
return $this->_contextPath;
}
public function getDirective()
{
return $this->_directive;
}
public function getHashCode()
{
return $this->_hashCode;
}
public function &getItems()
{
return $this->_tpl;
}
public function instantiateIn($tplControl,$parentControl=null)
{
$this->_tplControl=$tplControl;
if($parentControl===null)
$parentControl=$tplControl;
if(($page=$tplControl->getPage())===null)
$page=$this->getService()->getRequestedPage();
$controls=array();
$directChildren=array();
foreach($this->_tpl as $key=>$object)
{
if($object[0]===-1)
$parent=$parentControl;
else if(isset($controls[$object[0]]))
$parent=$controls[$object[0]];
else
continue;
if(isset($object[2])) {
$component=Prado::createComponent($object[1]);
$properties=&$object[2];
if($component instanceof TControl)
{
if($component instanceof TOutputCache)
$component->setCacheKeyPrefix($this->_hashCode.$key);
$component->setTemplateControl($tplControl);
if(isset($properties['id']))
{
if(is_array($properties['id']))
$properties['id']=$component->evaluateExpression($properties['id'][1]);
$tplControl->registerObject($properties['id'],$component);
}
if(isset($properties['skinid']))
{
if(is_array($properties['skinid']))
$component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
else
$component->setSkinID($properties['skinid']);
unset($properties['skinid']);
}
$component->trackViewState(false);
$component->applyStyleSheetSkin($page);
foreach($properties as $name=>$value)
$this->configureControl($component,$name,$value);
$component->trackViewState(true);
if($parent===$parentControl)
$directChildren[]=$component;
else
$component->createdOnTemplate($parent);
if($component->getAllowChildControls())
$controls[$key]=$component;
}
else if($component instanceof TComponent)
{
$controls[$key]=$component;
if(isset($properties['id']))
{
if(is_array($properties['id']))
$properties['id']=$component->evaluateExpression($properties['id'][1]);
$tplControl->registerObject($properties['id'],$component);
if(!$component->hasProperty('id'))
unset($properties['id']);
}
foreach($properties as $name=>$value)
$this->configureComponent($component,$name,$value);
if($parent===$parentControl)
$directChildren[]=$component;
else
$component->createdOnTemplate($parent);
}
}
else
{
if($object[1] instanceof TCompositeLiteral)
{
$o=clone $object[1];
$o->setContainer($tplControl);
if($parent===$parentControl)
$directChildren[]=$o;
else
$parent->addParsedObject($o);
}
else
{
if($parent===$parentControl)
$directChildren[]=$object[1];
else
$parent->addParsedObject($object[1]);
}
}
}
foreach($directChildren as $control)
{
if($control instanceof TComponent)
$control->createdOnTemplate($parentControl);
else
$parentControl->addParsedObject($control);
}
}
protected function configureControl($control,$name,$value)
{
if(strncasecmp($name,'on',2)===0) $this->configureEvent($control,$name,$value,$control);
else if(($pos=strrpos($name,'.'))===false) $this->configureProperty($control,$name,$value);
else $this->configureSubProperty($control,$name,$value);
}
protected function configureComponent($component,$name,$value)
{
if(strpos($name,'.')===false) $this->configureProperty($component,$name,$value);
else $this->configureSubProperty($component,$name,$value);
}
protected function configureEvent($control,$name,$value,$contextControl)
{
if(strpos($value,'.')===false)
$control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
else
$control->attachEventHandler($name,array($contextControl,$value));
}
protected function configureProperty($component,$name,$value)
{
if(is_array($value))
{
switch($value[0])
{
case self::CONFIG_DATABIND:
$component->bindProperty($name,$value[1]);
break;
case self::CONFIG_EXPRESSION:
if($component instanceof TControl)
$component->autoBindProperty($name,$value[1]);
else
{
$setter='set'.$name;
$component->$setter($this->_tplControl->evaluateExpression($value[1]));
}
break;
case self::CONFIG_TEMPLATE:
$setter='set'.$name;
$component->$setter($value[1]);
break;
case self::CONFIG_ASSET: $setter='set'.$name;
$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
$component->$setter($url);
break;
case self::CONFIG_PARAMETER: $setter='set'.$name;
$component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
break;
case self::CONFIG_LOCALIZATION:
$setter='set'.$name;
$component->$setter(Prado::localize($value[1]));
break;
default: throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
break;
}
}
else
{
if (substr($name,0,2)=='js')
if ($value and !($value instanceof TJavaScriptLiteral))
$value = new TJavaScriptLiteral($value);
$setter='set'.$name;
$component->$setter($value);
}
}
protected function configureSubProperty($component,$name,$value)
{
if(is_array($value))
{
switch($value[0])
{
case self::CONFIG_DATABIND: $component->bindProperty($name,$value[1]);
break;
case self::CONFIG_EXPRESSION: if($component instanceof TControl)
$component->autoBindProperty($name,$value[1]);
else
$component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
break;
case self::CONFIG_TEMPLATE:
$component->setSubProperty($name,$value[1]);
break;
case self::CONFIG_ASSET: $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
$component->setSubProperty($name,$url);
break;
case self::CONFIG_PARAMETER: $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
break;
case self::CONFIG_LOCALIZATION:
$component->setSubProperty($name,Prado::localize($value[1]));
break;
default: throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
break;
}
}
else
$component->setSubProperty($name,$value);
}
protected function parse($input)
{
$input=$this->preprocess($input);
$tpl=&$this->_tpl;
$n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
$expectPropEnd=false;
$textStart=0;
$stack=array();
$container=-1;
$matchEnd=0;
$c=0;
$this->_directive=null;
try
{
for($i=0;$i<$n;++$i)
{
$match=&$matches[$i];
$str=$match[0][0];
$matchStart=$match[0][1];
$matchEnd=$matchStart+strlen($str)-1;
if(strpos($str,'$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,'