3 * File Name: pradolite.php
4 * Last Update: 2016/08/23 12:44:08
5 * Generated By: buildscripts/phpbuilder/build.php
7 * This file is used in lieu of prado.php to boost PRADO application performance.
8 * It is generated by expanding prado.php with included files.
9 * Comments and trace statements are stripped off.
11 * Do not modify this file manually.
14 if(!defined('PRADO_DIR'))
15 define('PRADO_DIR',dirname(__FILE__));
16 if(!defined('PRADO_CHMOD'))
17 define('PRADO_CHMOD',0777);
20 const CLASS_FILE_EXT='.php';
21 private static $_aliases=array('System'=>PRADO_DIR);
22 private static $_usings=array();
23 private static $_application=null;
24 private static $_logger=null;
25 protected static $classExists = array();
26 public static function getVersion()
30 public static function initErrorHandlers()
32 set_error_handler(array('PradoBase','phpErrorHandler'));
33 register_shutdown_function(array('PradoBase','phpFatalErrorHandler'));
34 set_exception_handler(array('PradoBase','exceptionHandler'));
35 ini_set('display_errors', 0);
37 public static function autoload($className)
39 @include_once($className.self::CLASS_FILE_EXT);
41 public static function poweredByPrado($logoType=0)
43 $logoName=$logoType==1?'powered2':'powered';
44 if(self::$_application!==null)
46 $am=self::$_application->getAssetManager();
47 $url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
50 $url='http://pradosoft.github.io/docs/'.$logoName.'.gif';
51 return '<a title="Powered by PRADO" href="https://github.com/pradosoft/prado" target="_blank"><img src="'.$url.'" style="border-width:0px;" alt="Powered by PRADO" /></a>';
53 public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
55 if(error_reporting() & $errno)
56 throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
58 public static function phpFatalErrorHandler()
60 $error = error_get_last();
62 TPhpErrorException::isFatalError($error) &&
63 error_reporting() & $error['type'])
65 self::exceptionHandler(new TPhpErrorException($error['type'],$error['message'],$error['file'],$error['line']));
68 public static function exceptionHandler($exception)
70 if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
72 $errorHandler->handleError(null,$exception);
80 public static function setApplication($application)
82 if(self::$_application!==null && !defined('PRADO_TEST_RUN'))
83 throw new TInvalidOperationException('prado_application_singleton_required');
84 self::$_application=$application;
86 public static function getApplication()
88 return self::$_application;
90 public static function getFrameworkPath()
94 public static function createComponent($type)
96 if(!isset(self::$classExists[$type]))
97 self::$classExists[$type] = class_exists($type, false);
98 if( !isset(self::$_usings[$type]) && !self::$classExists[$type]) {
100 self::$classExists[$type] = class_exists($type, false);
102 if( ($pos = strrpos($type, '.')) !== false)
103 $type = substr($type,$pos+1);
104 if(($n=func_num_args())>1)
106 $args = func_get_args();
109 return new $type($args[1]);
112 return new $type($args[1], $args[2]);
115 return new $type($args[1], $args[2], $args[3]);
118 return new $type($args[1], $args[2], $args[3], $args[4]);
124 eval("\$component=new $type($s);");
132 public static function using($namespace,$checkClassExistence=true)
134 if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
136 if(($pos=strrpos($namespace,'.'))===false) {
139 include_once($namespace.self::CLASS_FILE_EXT);
143 if($checkClassExistence && !class_exists($namespace,false))
144 throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
149 else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
151 $className=substr($namespace,$pos+1);
152 if($className==='*') {
153 self::$_usings[$namespace]=$path;
154 set_include_path(get_include_path().PATH_SEPARATOR.$path);
157 self::$_usings[$namespace]=$path;
158 if(!$checkClassExistence || !class_exists($className,false))
166 if($checkClassExistence && !class_exists($className,false))
167 throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
175 throw new TInvalidDataValueException('prado_using_invalid',$namespace);
177 public static function getPathOfNamespace($namespace, $ext='')
179 if(self::CLASS_FILE_EXT === $ext || empty($ext))
181 if(isset(self::$_usings[$namespace]))
182 return self::$_usings[$namespace];
183 if(isset(self::$_aliases[$namespace]))
184 return self::$_aliases[$namespace];
186 $segs = explode('.',$namespace);
187 $alias = array_shift($segs);
188 if(null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias)))
189 return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file === '*') ? '' : DIRECTORY_SEPARATOR.$file.$ext);
192 public static function getPathOfAlias($alias)
194 return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
196 protected static function getPathAliases()
198 return self::$_aliases;
200 public static function setPathOfAlias($alias,$path)
202 if(isset(self::$_aliases[$alias]) && !defined('PRADO_TEST_RUN'))
203 throw new TInvalidOperationException('prado_alias_redefined',$alias);
204 else if(($rp=realpath($path))!==false && is_dir($rp))
206 if(strpos($alias,'.')===false)
207 self::$_aliases[$alias]=$rp;
209 throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
212 throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
214 public static function fatalError($msg)
216 echo '<h1>Fatal Error</h1>';
217 echo '<p>'.$msg.'</p>';
218 if(!function_exists('debug_backtrace'))
220 echo '<h2>Debug Backtrace</h2>';
223 foreach(debug_backtrace() as $t)
226 if($index==0) continue;
228 if(isset($t['file']))
229 echo basename($t['file']) . ':' . $t['line'];
231 echo '<PHP inner-code>';
233 if(isset($t['class']))
234 echo $t['class'] . $t['type'];
235 echo $t['function'] . '(';
236 if(isset($t['args']) && sizeof($t['args']) > 0)
239 foreach($t['args'] as $item)
243 $str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
244 if (strlen($item) > 70)
245 echo "'". substr($str, 0, 70) . "...'";
247 echo "'" . $str . "'";
249 else if (is_int($item) || is_float($item))
251 else if (is_object($item))
252 echo get_class($item);
253 else if (is_array($item))
254 echo 'array(' . count($item) . ')';
255 else if (is_bool($item))
256 echo $item ? 'true' : 'false';
257 else if ($item === null)
259 else if (is_resource($item))
260 echo get_resource_type($item);
262 if (count($t['args']) > $count)
271 public static function getUserLanguages()
273 static $languages=null;
274 if($languages===null)
276 if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
281 foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
283 $array=explode(';q=',trim($language));
284 $languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
287 $languages=array_keys($languages);
288 if(empty($languages))
294 public static function getPreferredLanguage()
296 static $language=null;
299 $langs=Prado::getUserLanguages();
300 $lang=explode('-',$langs[0]);
301 if(empty($lang[0]) || !ctype_alpha($lang[0]))
308 public static function trace($msg,$category='Uncategorized',$ctl=null)
310 if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
312 if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
314 $trace=debug_backtrace();
315 if(isset($trace[0]['file']) && isset($trace[0]['line']))
316 $msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
317 $level=TLogger::DEBUG;
320 $level=TLogger::INFO;
321 self::log($msg,$level,$category,$ctl);
323 public static function log($msg,$level=TLogger::INFO,$category='Uncategorized',$ctl=null)
325 if(self::$_logger===null)
326 self::$_logger=new TLogger;
327 self::$_logger->log($msg,$level,$category,$ctl);
329 public static function getLogger()
331 if(self::$_logger===null)
332 self::$_logger=new TLogger;
333 return self::$_logger;
335 public static function varDump($var,$depth=10,$highlight=false)
337 Prado::using('System.Util.TVarDumper');
338 return TVarDumper::dump($var,$depth,$highlight);
340 public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
342 Prado::using('System.I18N.Translation');
343 $app = Prado::getApplication()->getGlobalization(false);
345 foreach($parameters as $key => $value)
346 $params['{'.$key.'}'] = $value;
347 if($app===null || ($config = $app->getTranslationConfiguration())===null)
348 return strtr($text, $params);
349 if ($catalogue===null)
350 $catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
351 Translation::init($catalogue);
352 $appCharset = $app===null ? '' : $app->getCharset();
353 $defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
354 if(empty($charset)) $charset = $appCharset;
355 if(empty($charset)) $charset = $defaultCharset;
356 return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset);
359 PradoBase::using('System.TComponent');
360 PradoBase::using('System.Exceptions.TException');
361 PradoBase::using('System.Util.TLogger');
362 if(!class_exists('Prado',false))
364 class Prado extends PradoBase
368 spl_autoload_register(array('Prado','autoload'));
369 Prado::initErrorHandlers();
372 public function init($config);
373 public function getID();
374 public function setID($id);
378 public function init($config);
379 public function getID();
380 public function setID($id);
381 public function getEnabled();
382 public function setEnabled($value);
383 public function run();
385 interface ITextWriter
387 public function write($str);
388 public function flush();
392 public function getName();
393 public function setName($value);
394 public function getIsGuest();
395 public function setIsGuest($value);
396 public function getRoles();
397 public function setRoles($value);
398 public function isInRole($role);
399 public function saveToString();
400 public function loadFromString($string);
402 interface IStatePersister
404 public function load();
405 public function save($state);
409 public function get($id);
410 public function set($id,$value,$expire=0,$dependency=null);
411 public function add($id,$value,$expire=0,$dependency=null);
412 public function delete($id);
413 public function flush();
415 interface ICacheDependency
417 public function getHasChanged();
419 interface IRenderable
421 public function render($writer);
425 public function dataBind();
429 public function getHasStyle();
430 public function getStyle();
431 public function clearStyle();
433 interface IActiveControl
435 public function getActiveControl();
437 interface ICallbackEventHandler
439 public function raiseCallbackEvent($eventArgument);
441 interface IDataRenderer
443 public function getData();
444 public function setData($value);
446 class TApplicationComponent extends TComponent
448 public function getApplication()
450 return Prado::getApplication();
452 public function getService()
454 return Prado::getApplication()->getService();
456 public function getRequest()
458 return Prado::getApplication()->getRequest();
460 public function getResponse()
462 return Prado::getApplication()->getResponse();
464 public function getSession()
466 return Prado::getApplication()->getSession();
468 public function getUser()
470 return Prado::getApplication()->getUser();
472 public function publishAsset($assetPath,$className=null)
474 if($className===null)
475 $className=get_class($this);
476 $class=new ReflectionClass($className);
477 $fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath;
478 return $this->publishFilePath($fullPath);
480 public function publishFilePath($fullPath, $checkTimestamp=false)
482 return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath, $checkTimestamp);
485 abstract class TModule extends TApplicationComponent implements IModule
488 public function init($config)
491 public function getID()
495 public function setID($value)
500 abstract class TService extends TApplicationComponent implements IService
503 private $_enabled=true;
504 public function init($config)
507 public function getID()
511 public function setID($value)
515 public function getEnabled()
517 return $this->_enabled;
519 public function setEnabled($value)
521 $this->_enabled=TPropertyValue::ensureBoolean($value);
523 public function run()
527 class TErrorHandler extends TModule
529 const ERROR_FILE_NAME='error';
530 const EXCEPTION_FILE_NAME='exception';
531 const SOURCE_LINES=12;
532 private $_templatePath=null;
533 public function init($config)
535 $this->getApplication()->setErrorHandler($this);
537 public function getErrorTemplatePath()
539 if($this->_templatePath===null)
540 $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
541 return $this->_templatePath;
543 public function setErrorTemplatePath($value)
545 if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath))
546 $this->_templatePath=$templatePath;
548 throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value);
550 public function handleError($sender,$param)
552 static $handling=false;
553 restore_error_handler();
554 restore_exception_handler();
556 $this->handleRecursiveError($param);
560 if(($response=$this->getResponse())!==null)
563 header('Content-Type: text/html; charset=UTF-8');
564 if($param instanceof THttpException)
565 $this->handleExternalError($param->getStatusCode(),$param);
566 else if($this->getApplication()->getMode()===TApplicationMode::Debug)
567 $this->displayException($param);
569 $this->handleExternalError(500,$param);
572 protected static function hideSecurityRelated($value, $exception=null)
575 if($exception !== null && $exception instanceof Exception)
577 $aTrace = $exception->getTrace();
578 foreach($aTrace as $item)
580 if(isset($item['file']))
581 $aRpl[dirname($item['file']) . DIRECTORY_SEPARATOR] = '<hidden>' . DIRECTORY_SEPARATOR;
584 $aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}';
585 $aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}';
586 $aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR;
587 if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]);
588 $aRpl = array_reverse($aRpl, true);
589 return str_replace(array_keys($aRpl), $aRpl, $value);
591 protected function handleExternalError($statusCode,$exception)
593 if(!($exception instanceof THttpException))
594 error_log($exception->__toString());
595 $content=$this->getErrorTemplate($statusCode,$exception);
596 $serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
597 $isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug;
598 $errorMessage = $exception->getMessage();
600 $version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
604 $errorMessage = self::hideSecurityRelated($errorMessage, $exception);
607 '%%StatusCode%%' => "$statusCode",
608 '%%ErrorMessage%%' => htmlspecialchars($errorMessage),
609 '%%ServerAdmin%%' => $serverAdmin,
610 '%%Version%%' => $version,
611 '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
613 $this->getApplication()->getResponse()->setStatusCode($statusCode, $isDebug ? $exception->getMessage() : null);
614 echo strtr($content,$tokens);
616 protected function handleRecursiveError($exception)
618 if($this->getApplication()->getMode()===TApplicationMode::Debug)
620 echo "<html><head><title>Recursive Error</title></head>\n";
621 echo "<body><h1>Recursive Error</h1>\n";
622 echo "<pre>".$exception->__toString()."</pre>\n";
623 echo "</body></html>";
627 error_log("Error happened while processing an existing error:\n".$exception->__toString());
628 header('HTTP/1.0 500 Internal Error');
631 protected function displayException($exception)
633 if(php_sapi_name()==='cli')
635 echo $exception->getMessage()."\n";
636 echo $exception->getTraceAsString();
639 if($exception instanceof TTemplateException)
641 $fileName=$exception->getTemplateFile();
642 $lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
643 $source=$this->getSourceCode($lines,$exception->getLineNumber());
645 $fileName='---embedded template---';
646 $errorLine=$exception->getLineNumber();
650 if(($trace=$this->getExactTrace($exception))!==null)
652 $fileName=$trace['file'];
653 $errorLine=$trace['line'];
657 $fileName=$exception->getFile();
658 $errorLine=$exception->getLine();
660 $source=$this->getSourceCode(@file($fileName),$errorLine);
662 if($this->getApplication()->getMode()===TApplicationMode::Debug)
663 $version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
667 '%%ErrorType%%' => get_class($exception),
668 '%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
669 '%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
670 '%%SourceCode%%' => $source,
671 '%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
672 '%%Version%%' => $version,
673 '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
675 $content=$this->getExceptionTemplate($exception);
676 echo strtr($content,$tokens);
678 protected function getExceptionTemplate($exception)
680 $lang=Prado::getPreferredLanguage();
681 $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html';
682 if(!is_file($exceptionFile))
683 $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html';
684 if(($content=@file_get_contents($exceptionFile))===false)
685 die("Unable to open exception template file '$exceptionFile'.");
688 protected function getErrorTemplate($statusCode,$exception)
690 $base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME;
691 $lang=Prado::getPreferredLanguage();
692 if(is_file("$base$statusCode-$lang.html"))
693 $errorFile="$base$statusCode-$lang.html";
694 else if(is_file("$base$statusCode.html"))
695 $errorFile="$base$statusCode.html";
696 else if(is_file("$base-$lang.html"))
697 $errorFile="$base-$lang.html";
699 $errorFile="$base.html";
700 if(($content=@file_get_contents($errorFile))===false)
701 die("Unable to open error template file '$errorFile'.");
704 private function getExactTrace($exception)
706 $trace=$exception->getTrace();
708 if($exception instanceof TPhpErrorException)
710 if(isset($trace[0]['file']))
712 elseif(isset($trace[1]))
715 else if($exception instanceof TInvalidOperationException)
717 if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
718 $result=$this->getPropertyAccessTrace($trace,'__set');
720 if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
724 private function getPropertyAccessTrace($trace,$pattern)
727 foreach($trace as $t)
729 if(isset($t['function']) && $t['function']===$pattern)
736 private function getSourceCode($lines,$errorLine)
738 $beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
739 $endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
741 for($i=$beginLine;$i<$endLine;++$i)
743 if($i===$errorLine-1)
745 $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
746 $source.="<div class=\"error\">".$line."</div>";
749 $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
753 private function addLink($message)
755 $baseUrl='http://pradosoft.github.io/docs/manual/class-';
756 return preg_replace('/\b(T[A-Z]\w+)\b/',"<a href=\"$baseUrl\${1}\" target=\"_blank\">\${1}</a>",$message);
759 class TList extends TComponent implements IteratorAggregate,ArrayAccess,Countable
764 public function __construct($data=null,$readOnly=false)
767 $this->copyFrom($data);
768 $this->setReadOnly($readOnly);
770 public function getReadOnly()
774 protected function setReadOnly($value)
776 $this->_r=TPropertyValue::ensureBoolean($value);
778 public function getIterator()
780 return new ArrayIterator( $this->_d );
782 public function count()
784 return $this->getCount();
786 public function getCount()
790 public function itemAt($index)
792 if($index>=0 && $index<$this->_c)
793 return $this->_d[$index];
795 throw new TInvalidDataValueException('list_index_invalid',$index);
797 public function add($item)
799 $this->insertAt($this->_c,$item);
802 public function insertAt($index,$item)
806 if($index===$this->_c)
807 $this->_d[$this->_c++]=$item;
808 else if($index>=0 && $index<$this->_c)
810 array_splice($this->_d,$index,0,array($item));
814 throw new TInvalidDataValueException('list_index_invalid',$index);
817 throw new TInvalidOperationException('list_readonly',get_class($this));
819 public function remove($item)
823 if(($index=$this->indexOf($item))>=0)
825 $this->removeAt($index);
829 throw new TInvalidDataValueException('list_item_inexistent');
832 throw new TInvalidOperationException('list_readonly',get_class($this));
834 public function removeAt($index)
838 if($index>=0 && $index<$this->_c)
841 if($index===$this->_c)
842 return array_pop($this->_d);
845 $item=$this->_d[$index];
846 array_splice($this->_d,$index,1);
851 throw new TInvalidDataValueException('list_index_invalid',$index);
854 throw new TInvalidOperationException('list_readonly',get_class($this));
856 public function clear()
858 for($i=$this->_c-1;$i>=0;--$i)
861 public function contains($item)
863 return $this->indexOf($item)>=0;
865 public function indexOf($item)
867 if(($index=array_search($item,$this->_d,true))===false)
872 public function insertBefore($baseitem, $item)
876 if(($index = $this->indexOf($baseitem)) == -1)
877 throw new TInvalidDataValueException('list_item_inexistent');
878 $this->insertAt($index, $item);
882 throw new TInvalidOperationException('list_readonly',get_class($this));
884 public function insertAfter($baseitem, $item)
888 if(($index = $this->indexOf($baseitem)) == -1)
889 throw new TInvalidDataValueException('list_item_inexistent');
890 $this->insertAt($index + 1, $item);
894 throw new TInvalidOperationException('list_readonly',get_class($this));
896 public function toArray()
900 public function copyFrom($data)
902 if(is_array($data) || ($data instanceof Traversable))
906 foreach($data as $item)
909 else if($data!==null)
910 throw new TInvalidDataTypeException('list_data_not_iterable');
912 public function mergeWith($data)
914 if(is_array($data) || ($data instanceof Traversable))
916 foreach($data as $item)
919 else if($data!==null)
920 throw new TInvalidDataTypeException('list_data_not_iterable');
922 public function offsetExists($offset)
924 return ($offset>=0 && $offset<$this->_c);
926 public function offsetGet($offset)
928 return $this->itemAt($offset);
930 public function offsetSet($offset,$item)
932 if($offset===null || $offset===$this->_c)
933 $this->insertAt($this->_c,$item);
936 $this->removeAt($offset);
937 $this->insertAt($offset,$item);
940 public function offsetUnset($offset)
942 $this->removeAt($offset);
945 class TListIterator extends ArrayIterator
948 abstract class TCache extends TModule implements ICache, ArrayAccess
950 private $_prefix=null;
951 private $_primary=true;
952 public function init($config)
954 if($this->_prefix===null)
955 $this->_prefix=$this->getApplication()->getUniqueID();
958 if($this->getApplication()->getCache()===null)
959 $this->getApplication()->setCache($this);
961 throw new TConfigurationException('cache_primary_duplicated',get_class($this));
964 public function getPrimaryCache()
966 return $this->_primary;
968 public function setPrimaryCache($value)
970 $this->_primary=TPropertyValue::ensureBoolean($value);
972 public function getKeyPrefix()
974 return $this->_prefix;
976 public function setKeyPrefix($value)
978 $this->_prefix=$value;
980 protected function generateUniqueKey($key)
982 return md5($this->_prefix.$key);
984 public function get($id)
986 if(($data=$this->getValue($this->generateUniqueKey($id)))!==false)
990 if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
995 public function set($id,$value,$expire=0,$dependency=null)
997 if(empty($value) && $expire === 0)
1001 $data=array($value,$dependency);
1002 return $this->setValue($this->generateUniqueKey($id),$data,$expire);
1005 public function add($id,$value,$expire=0,$dependency=null)
1007 if(empty($value) && $expire === 0)
1009 $data=array($value,$dependency);
1010 return $this->addValue($this->generateUniqueKey($id),$data,$expire);
1012 public function delete($id)
1014 return $this->deleteValue($this->generateUniqueKey($id));
1016 public function flush()
1018 throw new TNotSupportedException('cache_flush_unsupported');
1020 abstract protected function getValue($key);
1021 abstract protected function setValue($key,$value,$expire);
1022 abstract protected function addValue($key,$value,$expire);
1023 abstract protected function deleteValue($key);
1024 public function offsetExists($id)
1026 return $this->get($id) !== false;
1028 public function offsetGet($id)
1030 return $this->get($id);
1032 public function offsetSet($id, $value)
1034 $this->set($id, $value);
1036 public function offsetUnset($id)
1041 abstract class TCacheDependency extends TComponent implements ICacheDependency
1044 class TFileCacheDependency extends TCacheDependency
1047 private $_timestamp;
1048 public function __construct($fileName)
1050 $this->setFileName($fileName);
1052 public function getFileName()
1054 return $this->_fileName;
1056 public function setFileName($value)
1058 $this->_fileName=$value;
1059 $this->_timestamp=@filemtime($value);
1061 public function getTimestamp()
1063 return $this->_timestamp;
1065 public function getHasChanged()
1067 return @filemtime($this->_fileName)!==$this->_timestamp;
1070 class TDirectoryCacheDependency extends TCacheDependency
1072 private $_recursiveCheck=true;
1073 private $_recursiveLevel=-1;
1074 private $_timestamps;
1075 private $_directory;
1076 public function __construct($directory)
1078 $this->setDirectory($directory);
1080 public function getDirectory()
1082 return $this->_directory;
1084 public function setDirectory($directory)
1086 if(($path=realpath($directory))===false || !is_dir($path))
1087 throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
1088 $this->_directory=$path;
1089 $this->_timestamps=$this->generateTimestamps($path);
1091 public function getRecursiveCheck()
1093 return $this->_recursiveCheck;
1095 public function setRecursiveCheck($value)
1097 $this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
1099 public function getRecursiveLevel()
1101 return $this->_recursiveLevel;
1103 public function setRecursiveLevel($value)
1105 $this->_recursiveLevel=TPropertyValue::ensureInteger($value);
1107 public function getHasChanged()
1109 return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
1111 protected function validateFile($fileName)
1115 protected function validateDirectory($directory)
1119 protected function generateTimestamps($directory,$level=0)
1121 if(($dir=opendir($directory))===false)
1122 throw new TIOException('directorycachedependency_directory_invalid',$directory);
1123 $timestamps=array();
1124 while(($file=readdir($dir))!==false)
1126 $path=$directory.DIRECTORY_SEPARATOR.$file;
1127 if($file==='.' || $file==='..')
1129 else if(is_dir($path))
1131 if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
1132 $timestamps=array_merge($this->generateTimestamps($path,$level+1));
1134 else if($this->validateFile($path))
1135 $timestamps[$path]=filemtime($path);
1141 class TGlobalStateCacheDependency extends TCacheDependency
1143 private $_stateName;
1144 private $_stateValue;
1145 public function __construct($name)
1147 $this->setStateName($name);
1149 public function getStateName()
1151 return $this->_stateName;
1153 public function setStateName($value)
1155 $this->_stateName=$value;
1156 $this->_stateValue=Prado::getApplication()->getGlobalState($value);
1158 public function getHasChanged()
1160 return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
1163 class TChainedCacheDependency extends TCacheDependency
1165 private $_dependencies=null;
1166 public function getDependencies()
1168 if($this->_dependencies===null)
1169 $this->_dependencies=new TCacheDependencyList;
1170 return $this->_dependencies;
1172 public function getHasChanged()
1174 if($this->_dependencies!==null)
1176 foreach($this->_dependencies as $dependency)
1177 if($dependency->getHasChanged())
1183 class TApplicationStateCacheDependency extends TCacheDependency
1185 public function getHasChanged()
1187 return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
1190 class TCacheDependencyList extends TList
1192 public function insertAt($index,$item)
1194 if($item instanceof ICacheDependency)
1195 parent::insertAt($index,$item);
1197 throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
1200 class TTextWriter extends TComponent implements ITextWriter
1203 public function flush()
1209 public function write($str)
1213 public function writeLine($str='')
1215 $this->write($str."\n");
1218 class TPriorityList extends TList
1220 private $_d=array();
1226 public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1228 parent::__construct();
1230 $this->copyFrom($data);
1231 $this->setReadOnly($readOnly);
1232 $this->setPrecision($precision);
1233 $this->setDefaultPriority($defaultPriority);
1235 public function count()
1237 return $this->getCount();
1239 public function getCount()
1243 public function getPriorityCount($priority=null)
1245 if($priority===null)
1246 $priority=$this->getDefaultPriority();
1247 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1248 if(!isset($this->_d[$priority]) || !is_array($this->_d[$priority]))
1250 return count($this->_d[$priority]);
1252 public function getDefaultPriority()
1256 protected function setDefaultPriority($value)
1258 $this->_dp=(string)round(TPropertyValue::ensureFloat($value),$this->_p);
1260 public function getPrecision()
1264 protected function setPrecision($value)
1266 $this->_p=TPropertyValue::ensureInteger($value);
1268 public function getIterator()
1270 return new ArrayIterator($this->flattenPriorities());
1272 public function getPriorities()
1274 $this->sortPriorities();
1275 return array_keys($this->_d);
1277 protected function sortPriorities() {
1279 ksort($this->_d,SORT_NUMERIC);
1283 protected function flattenPriorities() {
1284 if(is_array($this->_fd))
1286 $this->sortPriorities();
1288 foreach($this->_d as $priority => $itemsatpriority)
1289 $this->_fd=array_merge($this->_fd,$itemsatpriority);
1292 public function itemAt($index)
1294 if($index>=0&&$index<$this->getCount()) {
1295 $arr=$this->flattenPriorities();
1296 return $arr[$index];
1298 throw new TInvalidDataValueException('list_index_invalid',$index);
1300 public function itemsAtPriority($priority=null)
1302 if($priority===null)
1303 $priority=$this->getDefaultPriority();
1304 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1305 return isset($this->_d[$priority])?$this->_d[$priority]:null;
1307 public function itemAtIndexInPriority($index,$priority=null)
1309 if($priority===null)
1310 $priority=$this->getDefaultPriority();
1311 $priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
1312 return !isset($this->_d[$priority])?false:(
1313 isset($this->_d[$priority][$index])?$this->_d[$priority][$index]:false
1316 public function add($item,$priority=null)
1318 if($this->getReadOnly())
1319 throw new TInvalidOperationException('list_readonly',get_class($this));
1320 return $this->insertAtIndexInPriority($item,false,$priority,true);
1322 public function insertAt($index,$item)
1324 if($this->getReadOnly())
1325 throw new TInvalidOperationException('list_readonly',get_class($this));
1326 if(($priority=$this->priorityAt($index,true))!==false)
1327 $this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1329 throw new TInvalidDataValueException('list_index_invalid',$index);
1331 public function insertAtIndexInPriority($item,$index=false,$priority=null,$preserveCache=false)
1333 if($this->getReadOnly())
1334 throw new TInvalidOperationException('list_readonly',get_class($this));
1335 if($priority===null)
1336 $priority=$this->getDefaultPriority();
1337 $priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
1338 if($preserveCache) {
1339 $this->sortPriorities();
1341 foreach($this->_d as $prioritykey=>$items)
1342 if($prioritykey>=$priority)
1346 if($index===false&&isset($this->_d[$priority])) {
1347 $c=count($this->_d[$priority]);
1349 $this->_d[$priority][]=$item;
1350 } else if(isset($this->_d[$priority])) {
1352 array_splice($this->_d[$priority],$index,0,array($item));
1356 $this->_d[$priority]=array($item);
1358 if($this->_fd&&is_array($this->_fd)) array_splice($this->_fd,$c,0,array($item));
1361 if($index===false&&isset($this->_d[$priority])) {
1362 $cc=count($this->_d[$priority]);
1363 $this->_d[$priority][]=$item;
1364 } else if(isset($this->_d[$priority])) {
1366 array_splice($this->_d[$priority],$index,0,array($item));
1370 $this->_d[$priority]=array($item);
1372 if($this->_fd&&is_array($this->_fd)&&count($this->_d)==1)
1373 array_splice($this->_fd,$cc,0,array($item));
1380 public function remove($item,$priority=false)
1382 if($this->getReadOnly())
1383 throw new TInvalidOperationException('list_readonly',get_class($this));
1384 if(($p=$this->priorityOf($item,true))!==false)
1386 if($priority!==false) {
1387 if($priority===null)
1388 $priority=$this->getDefaultPriority();
1389 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1390 if($p[0]!=$priority)
1391 throw new TInvalidDataValueException('list_item_inexistent');
1393 $this->removeAtIndexInPriority($p[1],$p[0]);
1397 throw new TInvalidDataValueException('list_item_inexistent');
1399 public function removeAt($index)
1401 if($this->getReadOnly())
1402 throw new TInvalidOperationException('list_readonly',get_class($this));
1403 if(($priority=$this->priorityAt($index, true))!==false)
1404 return $this->removeAtIndexInPriority($priority[1],$priority[0]);
1405 throw new TInvalidDataValueException('list_index_invalid',$index);
1407 public function removeAtIndexInPriority($index, $priority=null)
1409 if($this->getReadOnly())
1410 throw new TInvalidOperationException('list_readonly',get_class($this));
1411 if($priority===null)
1412 $priority=$this->getDefaultPriority();
1413 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1414 if(!isset($this->_d[$priority])||$index<0||$index>=count($this->_d[$priority]))
1415 throw new TInvalidDataValueException('list_item_inexistent');
1416 $value=array_splice($this->_d[$priority],$index,1);
1418 if(!count($this->_d[$priority]))
1419 unset($this->_d[$priority]);
1424 public function clear()
1426 if($this->getReadOnly())
1427 throw new TInvalidOperationException('list_readonly',get_class($this));
1428 $d=array_reverse($this->_d,true);
1429 foreach($this->_d as $priority=>$items) {
1430 for($index=count($items)-1;$index>=0;$index--)
1431 $this->removeAtIndexInPriority($index,$priority);
1432 unset($this->_d[$priority]);
1435 public function contains($item)
1437 return $this->indexOf($item)>=0;
1439 public function indexOf($item)
1441 if(($index=array_search($item,$this->flattenPriorities(),true))===false)
1446 public function priorityOf($item,$withindex = false)
1448 $this->sortPriorities();
1450 foreach($this->_d as $priority=>$items) {
1451 if(($index=array_search($item,$items,true))!==false) {
1453 return $withindex?array($priority,$index,$absindex,
1454 'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1456 $absindex+=count($items);
1460 public function priorityAt($index,$withindex = false)
1462 if($index<0||$index>=$this->getCount())
1463 throw new TInvalidDataValueException('list_index_invalid',$index);
1465 $this->sortPriorities();
1466 foreach($this->_d as $priority=>$items) {
1467 if($index>=($c=count($items)))
1470 return $withindex?array($priority,$index,$absindex,
1471 'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1475 public function insertBefore($indexitem, $item)
1477 if($this->getReadOnly())
1478 throw new TInvalidOperationException('list_readonly',get_class($this));
1479 if(($priority=$this->priorityOf($indexitem,true))===false)
1480 throw new TInvalidDataValueException('list_item_inexistent');
1481 $this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1482 return $priority[2];
1484 public function insertAfter($indexitem, $item)
1486 if($this->getReadOnly())
1487 throw new TInvalidOperationException('list_readonly',get_class($this));
1488 if(($priority=$this->priorityOf($indexitem,true))===false)
1489 throw new TInvalidDataValueException('list_item_inexistent');
1490 $this->insertAtIndexInPriority($item,$priority[1]+1,$priority[0]);
1491 return $priority[2]+1;
1493 public function toArray()
1495 return $this->flattenPriorities();
1497 public function toPriorityArray()
1499 $this->sortPriorities();
1502 public function toArrayBelowPriority($priority,$inclusive=false)
1504 $this->sortPriorities();
1506 foreach($this->_d as $itemspriority=>$itemsatpriority)
1508 if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1510 $items=array_merge($items,$itemsatpriority);
1514 public function toArrayAbovePriority($priority,$inclusive=true)
1516 $this->sortPriorities();
1518 foreach($this->_d as $itemspriority=>$itemsatpriority)
1520 if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1522 $items=array_merge($items,$itemsatpriority);
1526 public function copyFrom($data)
1528 if($data instanceof TPriorityList)
1530 if($this->getCount()>0)
1532 foreach($data->getPriorities() as $priority)
1534 foreach($data->itemsAtPriority($priority) as $index=>$item)
1535 $this->insertAtIndexInPriority($item,$index,$priority);
1537 } else if(is_array($data)||$data instanceof Traversable) {
1538 if($this->getCount()>0)
1540 foreach($data as $key=>$item)
1542 } else if($data!==null)
1543 throw new TInvalidDataTypeException('map_data_not_iterable');
1545 public function mergeWith($data)
1547 if($data instanceof TPriorityList)
1549 foreach($data->getPriorities() as $priority)
1551 foreach($data->itemsAtPriority($priority) as $index=>$item)
1552 $this->insertAtIndexInPriority($item,false,$priority);
1555 else if(is_array($data)||$data instanceof Traversable)
1557 foreach($data as $priority=>$item)
1560 else if($data!==null)
1561 throw new TInvalidDataTypeException('map_data_not_iterable');
1563 public function offsetExists($offset)
1565 return ($offset>=0&&$offset<$this->getCount());
1567 public function offsetGet($offset)
1569 return $this->itemAt($offset);
1571 public function offsetSet($offset,$item)
1574 return $this->add($item);
1575 if($offset===$this->getCount()) {
1576 $priority=$this->priorityAt($offset-1,true);
1579 $priority=$this->priorityAt($offset,true);
1580 $this->removeAtIndexInPriority($priority[1],$priority[0]);
1582 $this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1584 public function offsetUnset($offset)
1586 $this->removeAt($offset);
1589 class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable
1591 private $_d=array();
1593 protected function _getZappableSleepProps(&$exprops)
1595 parent::_getZappableSleepProps($exprops);
1596 if ($this->_d===array())
1597 $exprops[] = "\0TMap\0_d";
1598 if ($this->_r===false)
1599 $exprops[] = "\0TMap\0_r";
1601 public function __construct($data=null,$readOnly=false)
1604 $this->copyFrom($data);
1605 $this->setReadOnly($readOnly);
1607 public function getReadOnly()
1611 protected function setReadOnly($value)
1613 $this->_r=TPropertyValue::ensureBoolean($value);
1615 public function getIterator()
1617 return new ArrayIterator( $this->_d );
1619 public function count()
1621 return $this->getCount();
1623 public function getCount()
1625 return count($this->_d);
1627 public function getKeys()
1629 return array_keys($this->_d);
1631 public function itemAt($key)
1633 return isset($this->_d[$key]) ? $this->_d[$key] : null;
1635 public function add($key,$value)
1638 $this->_d[$key]=$value;
1640 throw new TInvalidOperationException('map_readonly',get_class($this));
1642 public function remove($key)
1646 if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
1648 $value=$this->_d[$key];
1649 unset($this->_d[$key]);
1656 throw new TInvalidOperationException('map_readonly',get_class($this));
1658 public function clear()
1660 foreach(array_keys($this->_d) as $key)
1661 $this->remove($key);
1663 public function contains($key)
1665 return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
1667 public function toArray()
1671 public function copyFrom($data)
1673 if(is_array($data) || $data instanceof Traversable)
1675 if($this->getCount()>0)
1677 foreach($data as $key=>$value)
1678 $this->add($key,$value);
1680 else if($data!==null)
1681 throw new TInvalidDataTypeException('map_data_not_iterable');
1683 public function mergeWith($data)
1685 if(is_array($data) || $data instanceof Traversable)
1687 foreach($data as $key=>$value)
1688 $this->add($key,$value);
1690 else if($data!==null)
1691 throw new TInvalidDataTypeException('map_data_not_iterable');
1693 public function offsetExists($offset)
1695 return $this->contains($offset);
1697 public function offsetGet($offset)
1699 return $this->itemAt($offset);
1701 public function offsetSet($offset,$item)
1703 $this->add($offset,$item);
1705 public function offsetUnset($offset)
1707 $this->remove($offset);
1710 class TMapIterator extends ArrayIterator
1713 class TPriorityMap extends TMap
1715 private $_d=array();
1722 public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1725 $this->copyFrom($data);
1726 $this->setReadOnly($readOnly);
1727 $this->setPrecision($precision);
1728 $this->setDefaultPriority($defaultPriority);
1730 public function getReadOnly()
1734 protected function setReadOnly($value)
1736 $this->_r=TPropertyValue::ensureBoolean($value);
1738 public function getDefaultPriority()
1742 protected function setDefaultPriority($value)
1744 $this->_dp = (string)round(TPropertyValue::ensureFloat($value), $this->_p);
1746 public function getPrecision()
1750 protected function setPrecision($value)
1752 $this->_p=TPropertyValue::ensureInteger($value);
1754 public function getIterator()
1756 return new ArrayIterator($this->flattenPriorities());
1758 protected function sortPriorities() {
1760 ksort($this->_d, SORT_NUMERIC);
1764 protected function flattenPriorities() {
1765 if(is_array($this->_fd))
1767 $this->sortPriorities();
1768 $this->_fd = array();
1769 foreach($this->_d as $priority => $itemsatpriority)
1770 $this->_fd = array_merge($this->_fd, $itemsatpriority);
1773 public function count()
1775 return $this->getCount();
1777 public function getCount()
1781 public function getPriorityCount($priority=null)
1783 if($priority===null)
1784 $priority=$this->getDefaultPriority();
1785 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1786 if(!isset($this->_d[$priority])||!is_array($this->_d[$priority]))
1788 return count($this->_d[$priority]);
1790 public function getPriorities()
1792 $this->sortPriorities();
1793 return array_keys($this->_d);
1795 public function getKeys()
1797 return array_keys($this->flattenPriorities());
1799 public function itemAt($key,$priority=false)
1801 if($priority===false){
1802 $map=$this->flattenPriorities();
1803 return isset($map[$key])?$map[$key]:null;
1805 if($priority===null)
1806 $priority=$this->getDefaultPriority();
1807 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1808 return (isset($this->_d[$priority])&&isset($this->_d[$priority][$key]))?$this->_d[$priority][$key]:null;
1811 public function setPriorityAt($key,$priority=null)
1813 if($priority===null)
1814 $priority=$this->getDefaultPriority();
1815 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1816 $oldpriority=$this->priorityAt($key);
1817 if($oldpriority!==false&&$oldpriority!=$priority) {
1818 $value=$this->remove($key,$oldpriority);
1819 $this->add($key,$value,$priority);
1821 return $oldpriority;
1823 public function itemsAtPriority($priority=null)
1825 if($priority===null)
1826 $priority=$this->getDefaultPriority();
1827 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1828 return isset($this->_d[$priority])?$this->_d[$priority]:null;
1830 public function priorityOf($item)
1832 $this->sortPriorities();
1833 foreach($this->_d as $priority=>$items)
1834 if(($index=array_search($item,$items,true))!==false)
1838 public function priorityAt($key)
1840 $this->sortPriorities();
1841 foreach($this->_d as $priority=>$items)
1842 if(array_key_exists($key,$items))
1846 public function add($key,$value,$priority=null)
1848 if($priority===null)
1849 $priority=$this->getDefaultPriority();
1850 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1853 foreach($this->_d as $innerpriority=>$items)
1854 if(array_key_exists($key,$items))
1856 unset($this->_d[$innerpriority][$key]);
1858 if(count($this->_d[$innerpriority])===0)
1859 unset($this->_d[$innerpriority]);
1861 if(!isset($this->_d[$priority])) {
1862 $this->_d[$priority]=array($key=>$value);
1866 $this->_d[$priority][$key]=$value;
1871 throw new TInvalidOperationException('map_readonly',get_class($this));
1874 public function remove($key,$priority=false)
1878 if($priority===null)
1879 $priority=$this->getDefaultPriority();
1880 if($priority===false)
1882 $this->sortPriorities();
1883 foreach($this->_d as $priority=>$items)
1884 if(array_key_exists($key,$items))
1886 $value=$this->_d[$priority][$key];
1887 unset($this->_d[$priority][$key]);
1889 if(count($this->_d[$priority])===0)
1891 unset($this->_d[$priority]);
1901 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1902 if(isset($this->_d[$priority])&&(isset($this->_d[$priority][$key])||array_key_exists($key,$this->_d[$priority])))
1904 $value=$this->_d[$priority][$key];
1905 unset($this->_d[$priority][$key]);
1907 if(count($this->_d[$priority])===0) {
1908 unset($this->_d[$priority]);
1919 throw new TInvalidOperationException('map_readonly',get_class($this));
1921 public function clear()
1923 foreach($this->_d as $priority=>$items)
1924 foreach(array_keys($items) as $key)
1925 $this->remove($key);
1927 public function contains($key)
1929 $map=$this->flattenPriorities();
1930 return isset($map[$key])||array_key_exists($key,$map);
1932 public function toArray()
1934 return $this->flattenPriorities();
1936 public function toArrayBelowPriority($priority,$inclusive=false)
1938 $this->sortPriorities();
1940 foreach($this->_d as $itemspriority=>$itemsatpriority)
1942 if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1944 $items=array_merge($items,$itemsatpriority);
1948 public function toArrayAbovePriority($priority,$inclusive=true)
1950 $this->sortPriorities();
1952 foreach($this->_d as $itemspriority=>$itemsatpriority)
1954 if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1956 $items=array_merge($items,$itemsatpriority);
1960 public function copyFrom($data)
1962 if($data instanceof TPriorityMap)
1964 if($this->getCount()>0)
1966 foreach($data->getPriorities() as $priority) {
1967 foreach($data->itemsAtPriority($priority) as $key => $value) {
1968 $this->add($key,$value,$priority);
1972 else if(is_array($data)||$data instanceof Traversable)
1974 if($this->getCount()>0)
1976 foreach($data as $key=>$value)
1977 $this->add($key,$value);
1979 else if($data!==null)
1980 throw new TInvalidDataTypeException('map_data_not_iterable');
1982 public function mergeWith($data)
1984 if($data instanceof TPriorityMap)
1986 foreach($data->getPriorities() as $priority)
1988 foreach($data->itemsAtPriority($priority) as $key => $value)
1989 $this->add($key,$value,$priority);
1992 else if(is_array($data)||$data instanceof Traversable)
1994 foreach($data as $key=>$value)
1995 $this->add($key,$value);
1997 else if($data!==null)
1998 throw new TInvalidDataTypeException('map_data_not_iterable');
2000 public function offsetExists($offset)
2002 return $this->contains($offset);
2004 public function offsetGet($offset)
2006 return $this->itemAt($offset);
2008 public function offsetSet($offset,$item)
2010 $this->add($offset,$item);
2012 public function offsetUnset($offset)
2014 $this->remove($offset);
2017 class TStack extends TComponent implements IteratorAggregate,Countable
2019 private $_d=array();
2021 public function __construct($data=null)
2024 $this->copyFrom($data);
2026 public function toArray()
2030 public function copyFrom($data)
2032 if(is_array($data) || ($data instanceof Traversable))
2035 foreach($data as $item)
2041 else if($data!==null)
2042 throw new TInvalidDataTypeException('stack_data_not_iterable');
2044 public function clear()
2049 public function contains($item)
2051 return array_search($item,$this->_d,true)!==false;
2053 public function peek()
2056 throw new TInvalidOperationException('stack_empty');
2058 return $this->_d[$this->_c-1];
2060 public function pop()
2063 throw new TInvalidOperationException('stack_empty');
2067 return array_pop($this->_d);
2070 public function push($item)
2073 $this->_d[] = $item;
2075 public function getIterator()
2077 return new ArrayIterator( $this->_d );
2079 public function getCount()
2083 public function count()
2085 return $this->getCount();
2088 class TStackIterator implements Iterator
2093 public function __construct(&$data)
2097 $this->_c=count($this->_d);
2099 public function rewind()
2103 public function key()
2107 public function current()
2109 return $this->_d[$this->_i];
2111 public function next()
2115 public function valid()
2117 return $this->_i<$this->_c;
2120 class TXmlElement extends TComponent
2122 private $_parent=null;
2123 private $_tagName='unknown';
2125 private $_elements=null;
2126 private $_attributes=null;
2127 public function __construct($tagName)
2129 $this->setTagName($tagName);
2131 public function getParent()
2133 return $this->_parent;
2135 public function setParent($parent)
2137 $this->_parent=$parent;
2139 public function getTagName()
2141 return $this->_tagName;
2143 public function setTagName($tagName)
2145 $this->_tagName=$tagName;
2147 public function getValue()
2149 return $this->_value;
2151 public function setValue($value)
2153 $this->_value=TPropertyValue::ensureString($value);
2155 public function getHasElement()
2157 return $this->_elements!==null && $this->_elements->getCount()>0;
2159 public function getHasAttribute()
2161 return $this->_attributes!==null && $this->_attributes->getCount()>0;
2163 public function getAttribute($name)
2165 if($this->_attributes!==null)
2166 return $this->_attributes->itemAt($name);
2170 public function setAttribute($name,$value)
2172 $this->getAttributes()->add($name,TPropertyValue::ensureString($value));
2174 public function getElements()
2176 if(!$this->_elements)
2177 $this->_elements=new TXmlElementList($this);
2178 return $this->_elements;
2180 public function getAttributes()
2182 if(!$this->_attributes)
2183 $this->_attributes=new TMap;
2184 return $this->_attributes;
2186 public function getElementByTagName($tagName)
2188 if($this->_elements)
2190 foreach($this->_elements as $element)
2191 if($element->_tagName===$tagName)
2196 public function getElementsByTagName($tagName)
2199 if($this->_elements)
2201 foreach($this->_elements as $element)
2202 if($element->_tagName===$tagName)
2203 $list->add($element);
2207 public function toString($indent=0)
2210 if($this->_attributes!==null)
2212 foreach($this->_attributes as $name=>$value)
2214 $value=$this->xmlEncode($value);
2215 $attr.=" $name=\"$value\"";
2218 $prefix=str_repeat(' ',$indent*4);
2219 if($this->getHasElement())
2221 $str=$prefix."<{$this->_tagName}$attr>\n";
2222 foreach($this->getElements() as $element)
2223 $str.=$element->toString($indent+1)."\n";
2224 $str.=$prefix."</{$this->_tagName}>";
2227 else if(($value=$this->getValue())!=='')
2229 $value=$this->xmlEncode($value);
2230 return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>";
2233 return $prefix."<{$this->_tagName}$attr />";
2235 public function __toString()
2237 return $this->toString();
2239 private function xmlEncode($str)
2241 return strtr($str,array(
2251 class TXmlDocument extends TXmlElement
2255 public function __construct($version='1.0',$encoding='')
2257 parent::__construct('');
2258 $this->setVersion($version);
2259 $this->setEncoding($encoding);
2261 public function getVersion()
2263 return $this->_version;
2265 public function setVersion($version)
2267 $this->_version=$version;
2269 public function getEncoding()
2271 return $this->_encoding;
2273 public function setEncoding($encoding)
2275 $this->_encoding=$encoding;
2277 public function loadFromFile($file)
2279 if(($str=@file_get_contents($file))!==false)
2280 return $this->loadFromString($str);
2282 throw new TIOException('xmldocument_file_read_failed',$file);
2284 public function loadFromString($string)
2286 $doc=new DOMDocument();
2287 if($doc->loadXML($string)===false)
2289 $this->setEncoding($doc->encoding);
2290 $this->setVersion($doc->xmlVersion);
2291 $element=$doc->documentElement;
2292 $this->setTagName($element->tagName);
2293 $this->setValue($element->nodeValue);
2294 $elements=$this->getElements();
2295 $attributes=$this->getAttributes();
2297 $attributes->clear();
2299 if($bSimpleXml === null)
2300 $bSimpleXml = (boolean)function_exists('simplexml_load_string');
2303 $simpleDoc = simplexml_load_string($string);
2304 $docNamespaces = $simpleDoc->getDocNamespaces(false);
2306 foreach($docNamespaces as $prefix => $uri)
2309 $attributes->add('xmlns', $uri);
2311 $attributes->add('xmlns:'.$prefix, $uri);
2314 foreach($element->attributes as $name=>$attr)
2315 $attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value);
2316 foreach($element->childNodes as $child)
2318 if($child instanceof DOMElement)
2319 $elements->add($this->buildElement($child));
2323 public function saveToFile($file)
2325 if(($fw=fopen($file,'w'))!==false)
2327 fwrite($fw,$this->saveToString());
2331 throw new TIOException('xmldocument_file_write_failed',$file);
2333 public function saveToString()
2335 $version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
2336 $encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
2337 return "<?xml{$version}{$encoding}?>\n".$this->toString(0);
2339 public function __toString()
2341 return $this->saveToString();
2343 protected function buildElement($node)
2345 $element=new TXmlElement($node->tagName);
2346 $element->setValue($node->nodeValue);
2347 foreach($node->attributes as $name=>$attr)
2348 $element->getAttributes()->add(($attr->prefix === '' ? '' : $attr->prefix . ':') . $name,$attr->value);
2349 foreach($node->childNodes as $child)
2351 if($child instanceof DOMElement)
2352 $element->getElements()->add($this->buildElement($child));
2357 class TXmlElementList extends TList
2360 public function __construct(TXmlElement $owner)
2364 protected function getOwner()
2368 public function insertAt($index,$item)
2370 if($item instanceof TXmlElement)
2372 parent::insertAt($index,$item);
2373 if($item->getParent()!==null)
2374 $item->getParent()->getElements()->remove($item);
2375 $item->setParent($this->_o);
2378 throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
2380 public function removeAt($index)
2382 $item=parent::removeAt($index);
2383 if($item instanceof TXmlElement)
2384 $item->setParent(null);
2388 class TAuthorizationRule extends TComponent
2397 private $_authenticated;
2398 public function __construct($action,$users,$roles,$verb='',$ipRules='')
2400 $action=strtolower(trim($action));
2401 if($action==='allow' || $action==='deny')
2402 $this->_action=$action;
2404 throw new TInvalidDataValueException('authorizationrule_action_invalid',$action);
2405 $this->_users=array();
2406 $this->_roles=array();
2407 $this->_ipRules=array();
2408 $this->_everyone=false;
2409 $this->_guest=false;
2410 $this->_authenticated=false;
2411 if(trim($users)==='')
2413 foreach(explode(',',$users) as $user)
2415 if(($user=trim(strtolower($user)))!=='')
2419 $this->_everyone=true;
2422 else if($user==='?')
2424 else if($user==='@')
2425 $this->_authenticated=true;
2427 $this->_users[]=$user;
2430 if(trim($roles)==='')
2432 foreach(explode(',',$roles) as $role)
2434 if(($role=trim(strtolower($role)))!=='')
2435 $this->_roles[]=$role;
2437 if(($verb=trim(strtolower($verb)))==='')
2439 if($verb==='*' || $verb==='get' || $verb==='post')
2442 throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb);
2443 if(trim($ipRules)==='')
2445 foreach(explode(',',$ipRules) as $ipRule)
2447 if(($ipRule=trim($ipRule))!=='')
2448 $this->_ipRules[]=$ipRule;
2451 public function getAction()
2453 return $this->_action;
2455 public function getUsers()
2457 return $this->_users;
2459 public function getRoles()
2461 return $this->_roles;
2463 public function getVerb()
2465 return $this->_verb;
2467 public function getIPRules()
2469 return $this->_ipRules;
2471 public function getGuestApplied()
2473 return $this->_guest || $this->_everyone;
2475 public function getEveryoneApplied()
2477 return $this->_everyone;
2479 public function getAuthenticatedApplied()
2481 return $this->_authenticated || $this->_everyone;
2483 public function isUserAllowed(IUser $user,$verb,$ip)
2485 if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user))
2486 return ($this->_action==='allow')?1:-1;
2490 private function isIpMatched($ip)
2492 if(empty($this->_ipRules))
2494 foreach($this->_ipRules as $rule)
2496 if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0))
2501 private function isUserMatched($user)
2503 return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users));
2505 private function isRoleMatched($user)
2507 foreach($this->_roles as $role)
2509 if($role==='*' || $user->isInRole($role))
2514 private function isVerbMatched($verb)
2516 return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0);
2519 class TAuthorizationRuleCollection extends TList
2521 public function isUserAllowed($user,$verb,$ip)
2523 if($user instanceof IUser)
2525 $verb=strtolower(trim($verb));
2526 foreach($this as $rule)
2528 if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0)
2529 return ($decision>0);
2536 public function insertAt($index,$item)
2538 if($item instanceof TAuthorizationRule)
2539 parent::insertAt($index,$item);
2541 throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required');
2544 class TSecurityManager extends TModule
2546 const STATE_VALIDATION_KEY = 'prado:securitymanager:validationkey';
2547 const STATE_ENCRYPTION_KEY = 'prado:securitymanager:encryptionkey';
2548 private $_validationKey = null;
2549 private $_encryptionKey = null;
2550 private $_hashAlgorithm = 'sha1';
2551 private $_cryptAlgorithm = 'rijndael-256';
2553 public function init($config)
2555 $this->_mbstring=extension_loaded('mbstring');
2556 $this->getApplication()->setSecurityManager($this);
2558 protected function generateRandomKey()
2560 return sprintf('%08x%08x%08x%08x',mt_rand(),mt_rand(),mt_rand(),mt_rand());
2562 public function getValidationKey()
2564 if(null === $this->_validationKey) {
2565 if(null === ($this->_validationKey = $this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))) {
2566 $this->_validationKey = $this->generateRandomKey();
2567 $this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY, $this->_validationKey, null, true);
2570 return $this->_validationKey;
2572 public function setValidationKey($value)
2575 throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
2576 $this->_validationKey = $value;
2578 public function getEncryptionKey()
2580 if(null === $this->_encryptionKey) {
2581 if(null === ($this->_encryptionKey = $this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))) {
2582 $this->_encryptionKey = $this->generateRandomKey();
2583 $this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY, $this->_encryptionKey, null, true);
2586 return $this->_encryptionKey;
2588 public function setEncryptionKey($value)
2591 throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
2592 $this->_encryptionKey = $value;
2594 public function getValidation()
2596 return $this->_hashAlgorithm;
2598 public function getHashAlgorithm()
2600 return $this->_hashAlgorithm;
2602 public function setValidation($value)
2604 $this->_hashAlgorithm = TPropertyValue::ensureEnum($value, 'TSecurityManagerValidationMode');
2606 public function setHashAlgorithm($value)
2608 $this->_hashAlgorithm = TPropertyValue::ensureString($value);
2610 public function getEncryption()
2612 if(is_string($this->_cryptAlgorithm))
2613 return $this->_cryptAlgorithm;
2616 public function setEncryption($value)
2618 $this->_cryptAlgorithm = $value;
2620 public function getCryptAlgorithm()
2622 return $this->_cryptAlgorithm;
2624 public function setCryptAlgorithm($value)
2626 $this->_cryptAlgorithm = $value;
2628 public function encrypt($data)
2630 $module=$this->openCryptModule();
2631 $key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
2633 $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
2634 mcrypt_generic_init($module, $key, $iv);
2635 $encrypted = $iv.mcrypt_generic($module, $data);
2636 mcrypt_generic_deinit($module);
2637 mcrypt_module_close($module);
2640 public function decrypt($data)
2642 $module=$this->openCryptModule();
2643 $key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
2644 $ivSize = mcrypt_enc_get_iv_size($module);
2645 $iv = $this->substr($data, 0, $ivSize);
2646 mcrypt_generic_init($module, $key, $iv);
2647 $decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data)));
2648 mcrypt_generic_deinit($module);
2649 mcrypt_module_close($module);
2652 protected function openCryptModule()
2654 if(extension_loaded('mcrypt'))
2656 if(is_array($this->_cryptAlgorithm))
2657 $module=@call_user_func_array('mcrypt_module_open',$this->_cryptAlgorithm);
2659 $module=@mcrypt_module_open($this->_cryptAlgorithm,'', MCRYPT_MODE_CBC,'');
2661 throw new TNotSupportedException('securitymanager_mcryptextension_initfailed');
2665 throw new TNotSupportedException('securitymanager_mcryptextension_required');
2667 public function hashData($data)
2669 $hmac = $this->computeHMAC($data);
2672 public function validateData($data)
2674 $len=$this->strlen($this->computeHMAC('test'));
2675 if($this->strlen($data) < $len)
2677 $hmac = $this->substr($data, 0, $len);
2678 $data2=$this->substr($data, $len, $this->strlen($data));
2679 return $hmac === $this->computeHMAC($data2) ? $data2 : false;
2681 protected function computeHMAC($data)
2683 $key = $this->getValidationKey();
2684 if(function_exists('hash_hmac'))
2685 return hash_hmac($this->_hashAlgorithm, $data, $key);
2686 if(!strcasecmp($this->_hashAlgorithm,'sha1'))
2694 $key = str_pad($func($key), 64, chr(0));
2695 return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
2697 private function strlen($string)
2699 return $this->_mbstring ? mb_strlen($string,'8bit') : strlen($string);
2701 private function substr($string,$start,$length)
2703 return $this->_mbstring ? mb_substr($string,$start,$length,'8bit') : substr($string,$start,$length);
2706 class TSecurityManagerValidationMode extends TEnumerable
2709 const SHA1 = 'SHA1';
2713 private static $_encodeTable=array('<'=>'<','>'=>'>','"'=>'"');
2714 private static $_decodeTable=array('<'=>'<','>'=>'>','"'=>'"');
2715 private static $_stripTable=array('<'=>'','>'=>'','"'=>'');
2716 public static function htmlEncode($s)
2718 return strtr($s,self::$_encodeTable);
2720 public static function htmlDecode($s)
2722 return strtr($s,self::$_decodeTable);
2724 public static function htmlStrip($s)
2726 return strtr($s,self::$_stripTable);
2731 public static function renderScriptFiles($files)
2734 foreach($files as $file)
2735 $str.= self::renderScriptFile($file);
2738 public static function renderScriptFile($file)
2740 return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
2742 public static function renderScriptBlocks($scripts)
2745 return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
2749 public static function renderScriptBlocksCallback($scripts)
2752 return implode("\n",$scripts)."\n";
2756 public static function renderScriptBlock($script)
2758 return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
2760 public static function quoteString($js)
2762 return self::jsonEncode($js,JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG);
2764 public static function quoteJsLiteral($js)
2766 if($js instanceof TJavaScriptLiteral)
2769 return new TJavaScriptLiteral($js);
2771 public static function quoteFunction($js)
2773 return self::quoteJsLiteral($js);
2775 public static function isJsLiteral($js)
2777 return ($js instanceof TJavaScriptLiteral);
2779 public static function isFunction($js)
2781 return self::isJsLiteral($js);
2783 public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
2785 if(is_string($value))
2786 return self::quoteString($value);
2787 else if(is_bool($value))
2788 return $value?'true':'false';
2789 else if(is_array($value))
2792 if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
2794 foreach($value as $k=>$v)
2796 if($v!=='' || $encodeEmptyStrings)
2800 $results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings);
2803 return '{'.$results.'}';
2807 foreach($value as $v)
2809 if($v!=='' || $encodeEmptyStrings)
2813 $results.=self::encode($v,$toMap, $encodeEmptyStrings);
2816 return '['.$results.']';
2819 else if(is_integer($value))
2821 else if(is_float($value))
2826 return 'Number.NEGATIVE_INFINITY';
2829 return 'Number.POSITIVE_INFINITY';
2832 $locale=localeConv();
2833 if($locale['decimal_point']=='.')
2836 return str_replace($locale['decimal_point'], '.', "$value");
2840 else if(is_object($value))
2841 if ($value instanceof TJavaScriptLiteral)
2842 return $value->toJavaScriptLiteral();
2844 return self::encode(get_object_vars($value),$toMap);
2845 else if($value===null)
2850 public static function jsonEncode($value, $options = 0)
2852 if (($g=Prado::getApplication()->getGlobalization(false))!==null &&
2853 strtoupper($enc=$g->getCharset())!='UTF-8') {
2854 self::convertToUtf8($value, $enc);
2856 $s = @json_encode($value,$options);
2857 self::checkJsonError();
2860 private static function convertToUtf8(&$value, $sourceEncoding) {
2861 if(is_string($value))
2862 $value=iconv($sourceEncoding, 'UTF-8', $value);
2863 else if (is_array($value))
2865 foreach($value as &$element)
2866 self::convertToUtf8($element, $sourceEncoding);
2869 public static function jsonDecode($value, $assoc = false, $depth = 512)
2871 $s= @json_decode($value, $assoc, $depth);
2872 self::checkJsonError();
2875 private static function checkJsonError()
2877 switch ($err = json_last_error())
2879 case JSON_ERROR_NONE:
2882 case JSON_ERROR_DEPTH:
2883 $msg = 'Maximum stack depth exceeded';
2885 case JSON_ERROR_STATE_MISMATCH:
2886 $msg = 'Underflow or the modes mismatch';
2888 case JSON_ERROR_CTRL_CHAR:
2889 $msg = 'Unexpected control character found';
2891 case JSON_ERROR_SYNTAX:
2892 $msg = 'Syntax error, malformed JSON';
2894 case JSON_ERROR_UTF8:
2895 $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
2898 $msg = 'Unknown error';
2901 throw new Exception("JSON error ($err): $msg");
2903 public static function JSMin($code)
2905 Prado::using('System.Web.Javascripts.JSMin');
2906 return JSMin::minify($code);
2909 class TUrlManager extends TModule
2911 public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
2913 $url=$serviceID.'='.urlencode($serviceParam);
2914 $amp=$encodeAmpersand?'&':'&';
2915 $request=$this->getRequest();
2916 if(is_array($getItems) || $getItems instanceof Traversable)
2920 foreach($getItems as $name=>$value)
2922 if(is_array($value))
2924 $name=urlencode($name.'[]');
2925 foreach($value as $v)
2926 $url.=$amp.$name.'='.urlencode($v);
2929 $url.=$amp.urlencode($name).'='.urlencode($value);
2934 foreach($getItems as $name=>$value)
2936 if(is_array($value))
2938 foreach($value as $v)
2939 $url.=$amp.$name.'[]='.$v;
2942 $url.=$amp.$name.'='.$value;
2946 switch($request->getUrlFormat())
2948 case THttpRequestUrlFormat::Path:
2949 return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
2950 case THttpRequestUrlFormat::HiddenPath:
2951 return rtrim(dirname($request->getApplicationUrl()), '/').'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
2953 return $request->getApplicationUrl().'?'.$url;
2956 public function parseUrl()
2958 $request=$this->getRequest();
2959 $pathInfo=trim($request->getPathInfo(),'/');
2960 if(($request->getUrlFormat()===THttpRequestUrlFormat::Path ||
2961 $request->getUrlFormat()===THttpRequestUrlFormat::HiddenPath) &&
2964 $separator=$request->getUrlParamSeparator();
2965 $paths=explode('/',$pathInfo);
2966 $getVariables=array();
2967 foreach($paths as $path)
2969 if(($path=trim($path))!=='')
2971 if(($pos=strpos($path,$separator))!==false)
2973 $name=substr($path,0,$pos);
2974 $value=substr($path,$pos+1);
2975 if(($pos=strpos($name,'[]'))!==false)
2976 $getVariables[substr($name,0,$pos)][]=$value;
2978 $getVariables[$name]=$value;
2981 $getVariables[$path]='';
2984 return $getVariables;
2990 class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
2992 const CGIFIX__PATH_INFO = 1;
2993 const CGIFIX__SCRIPT_NAME = 2;
2994 private $_urlManager=null;
2995 private $_urlManagerID='';
2996 private $_separator=',';
2997 private $_serviceID=null;
2998 private $_serviceParam=null;
2999 private $_cookies=null;
3000 private $_requestUri;
3002 private $_cookieOnly=null;
3003 private $_urlFormat=THttpRequestUrlFormat::Get;
3005 private $_requestResolved=false;
3006 private $_enableCookieValidation=false;
3008 private $_enableCache=false;
3011 private $_items=array();
3012 public function getID()
3016 public function setID($value)
3020 public function init($config)
3022 if(php_sapi_name()==='cli')
3024 $_SERVER['REMOTE_ADDR']='127.0.0.1';
3025 $_SERVER['REQUEST_METHOD']='GET';
3026 $_SERVER['SERVER_NAME']='localhost';
3027 $_SERVER['SERVER_PORT']=80;
3028 $_SERVER['HTTP_USER_AGENT']='';
3030 if(isset($_SERVER['REQUEST_URI']))
3031 $this->_requestUri=$_SERVER['REQUEST_URI'];
3032 else $this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
3033 if($this->_cgiFix&self::CGIFIX__PATH_INFO && isset($_SERVER['ORIG_PATH_INFO']))
3034 $this->_pathInfo=substr($_SERVER['ORIG_PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
3035 elseif(isset($_SERVER['PATH_INFO']))
3036 $this->_pathInfo=$_SERVER['PATH_INFO'];
3037 else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
3038 $this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
3040 $this->_pathInfo='';
3041 if(get_magic_quotes_gpc())
3044 $_GET=$this->stripSlashes($_GET);
3046 $_POST=$this->stripSlashes($_POST);
3047 if(isset($_REQUEST))
3048 $_REQUEST=$this->stripSlashes($_REQUEST);
3050 $_COOKIE=$this->stripSlashes($_COOKIE);
3052 $this->getApplication()->setRequest($this);
3054 public function stripSlashes(&$data)
3056 return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
3058 public function getUrl()
3060 if($this->_url===null)
3062 $secure=$this->getIsSecureConnection();
3063 $url=$secure?'https://':'http://';
3064 if(empty($_SERVER['HTTP_HOST']))
3066 $url.=$_SERVER['SERVER_NAME'];
3067 $port=$_SERVER['SERVER_PORT'];
3068 if(($port!=80 && !$secure) || ($port!=443 && $secure))
3072 $url.=$_SERVER['HTTP_HOST'];
3073 $url.=$this->getRequestUri();
3074 $this->_url=new TUri($url);
3078 public function setEnableCache($value)
3080 $this->_enableCache = TPropertyValue::ensureBoolean($value);
3082 public function getEnableCache()
3084 return $this->_enableCache;
3086 protected function getCacheKey()
3088 return $this->getID();
3090 protected function cacheUrlManager($manager)
3092 if($this->getEnableCache())
3094 $cache = $this->getApplication()->getCache();
3097 $dependencies = null;
3098 if($this->getApplication()->getMode() !== TApplicationMode::Performance)
3099 if ($manager instanceof TUrlMapping && $fn = $manager->getConfigFile())
3101 $fn = Prado::getPathOfNamespace($fn,$this->getApplication()->getConfigurationFileExt());
3102 $dependencies = new TFileCacheDependency($fn);
3104 return $cache->set($this->getCacheKey(), $manager, 0, $dependencies);
3109 protected function loadCachedUrlManager()
3111 if($this->getEnableCache())
3113 $cache = $this->getApplication()->getCache();
3116 $manager = $cache->get($this->getCacheKey());
3117 if($manager instanceof TUrlManager)
3123 public function getUrlManager()
3125 return $this->_urlManagerID;
3127 public function setUrlManager($value)
3129 $this->_urlManagerID=$value;
3131 public function getUrlManagerModule()
3133 if($this->_urlManager===null)
3135 if(($this->_urlManager = $this->loadCachedUrlManager())===null)
3137 if(empty($this->_urlManagerID))
3139 $this->_urlManager=new TUrlManager;
3140 $this->_urlManager->init(null);
3144 $this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
3145 if($this->_urlManager===null)
3146 throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
3147 if(!($this->_urlManager instanceof TUrlManager))
3148 throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
3150 $this->cacheUrlManager($this->_urlManager);
3153 return $this->_urlManager;
3155 public function getUrlFormat()
3157 return $this->_urlFormat;
3159 public function setUrlFormat($value)
3161 $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
3163 public function getUrlParamSeparator()
3165 return $this->_separator;
3167 public function setUrlParamSeparator($value)
3169 if(strlen($value)===1)
3170 $this->_separator=$value;
3172 throw new TInvalidDataValueException('httprequest_separator_invalid');
3174 public function getRequestType()
3176 return isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:null;
3178 public function getContentType($mimetypeOnly = true)
3180 if(!isset($_SERVER['CONTENT_TYPE']))
3182 if($mimetypeOnly === true && ($_pos = strpos(';', $_SERVER['CONTENT_TYPE'])) !== false)
3183 return substr($_SERVER['CONTENT_TYPE'], 0, $_pos);
3184 return $_SERVER['CONTENT_TYPE'];
3186 public function getIsSecureConnection()
3188 return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
3190 public function getPathInfo()
3192 return $this->_pathInfo;
3194 public function getQueryString()
3196 return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:null;
3198 public function getHttpProtocolVersion()
3200 return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:null;
3202 public function getHeaders($case=null)
3205 if($result === null && function_exists('apache_request_headers')) {
3206 $result = apache_request_headers();
3208 elseif($result === null) {
3210 foreach($_SERVER as $key=>$value) {
3211 if(strncasecmp($key, 'HTTP_', 5) !== 0) continue;
3212 $key = str_replace(' ','-', ucwords(strtolower(str_replace('_',' ', substr($key, 5)))));
3213 $result[$key] = $value;
3217 return array_change_key_case($result, $case);
3220 public function getRequestUri()
3222 return $this->_requestUri;
3224 public function getBaseUrl($forceSecureConnection=null)
3226 $url=$this->getUrl();
3227 $scheme=($forceSecureConnection)?"https": (($forceSecureConnection === null)?$url->getScheme():'http');
3228 $host=$url->getHost();
3229 if (($port=$url->getPort())) $host.=':'.$port;
3230 return $scheme.'://'.$host;
3232 public function getApplicationUrl()
3234 if($this->_cgiFix&self::CGIFIX__SCRIPT_NAME && isset($_SERVER['ORIG_SCRIPT_NAME']))
3235 return $_SERVER['ORIG_SCRIPT_NAME'];
3236 return isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:null;
3238 public function getAbsoluteApplicationUrl($forceSecureConnection=null)
3240 return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
3242 public function getApplicationFilePath()
3244 return realpath(isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:null);
3246 public function getServerName()
3248 return isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:null;
3250 public function getServerPort()
3252 return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null;
3254 public function getUrlReferrer()
3256 return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
3258 public function getBrowser()
3262 return get_browser();
3264 catch(TPhpErrorException $e)
3266 throw new TConfigurationException('httprequest_browscap_required');
3269 public function getUserAgent()
3271 return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
3273 public function getUserHostAddress()
3275 return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null;
3277 public function getUserHost()
3279 return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
3281 public function getAcceptTypes()
3283 return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
3285 public function getUserLanguages()
3287 return Prado::getUserLanguages();
3289 public function getEnableCookieValidation()
3291 return $this->_enableCookieValidation;
3293 public function setEnableCookieValidation($value)
3295 $this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
3297 public function getCgiFix()
3299 return $this->_cgiFix;
3301 public function setCgiFix($value)
3303 $this->_cgiFix=TPropertyValue::ensureInteger($value);
3305 public function getCookies()
3307 if($this->_cookies===null)
3309 $this->_cookies=new THttpCookieCollection;
3310 if($this->getEnableCookieValidation())
3312 $sm=$this->getApplication()->getSecurityManager();
3313 foreach($_COOKIE as $key=>$value)
3315 if(($value=$sm->validateData($value))!==false)
3316 $this->_cookies->add(new THttpCookie($key,$value));
3321 foreach($_COOKIE as $key=>$value)
3322 $this->_cookies->add(new THttpCookie($key,$value));
3325 return $this->_cookies;
3327 public function getUploadedFiles()
3331 public function getServerVariables()
3335 public function getEnvironmentVariables()
3339 public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
3341 if ($this->_cookieOnly===null)
3342 $this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
3343 $url=$this->getUrlManagerModule()->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
3344 if(defined('SID') && SID != '' && !$this->_cookieOnly)
3345 return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&':'&')) . SID;
3349 protected function parseUrl()
3351 return $this->getUrlManagerModule()->parseUrl();
3353 public function resolveRequest($serviceIDs)
3355 $getParams=$this->parseUrl();
3356 foreach($getParams as $name=>$value)
3357 $_GET[$name]=$value;
3358 $this->_items=array_merge($_GET,$_POST);
3359 $this->_requestResolved=true;
3360 foreach($serviceIDs as $serviceID)
3362 if($this->contains($serviceID))
3364 $this->setServiceID($serviceID);
3365 $this->setServiceParameter($this->itemAt($serviceID));
3371 public function getRequestResolved()
3373 return $this->_requestResolved;
3375 public function getServiceID()
3377 return $this->_serviceID;
3379 public function setServiceID($value)
3381 $this->_serviceID=$value;
3383 public function getServiceParameter()
3385 return $this->_serviceParam;
3387 public function setServiceParameter($value)
3389 $this->_serviceParam=$value;
3391 public function getIterator()
3393 return new ArrayIterator($this->_items);
3395 public function getCount()
3397 return count($this->_items);
3399 public function count()
3401 return $this->getCount();
3403 public function getKeys()
3405 return array_keys($this->_items);
3407 public function itemAt($key)
3409 return isset($this->_items[$key]) ? $this->_items[$key] : null;
3411 public function add($key,$value)
3413 $this->_items[$key]=$value;
3415 public function remove($key)
3417 if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
3419 $value=$this->_items[$key];
3420 unset($this->_items[$key]);
3426 public function clear()
3428 foreach(array_keys($this->_items) as $key)
3429 $this->remove($key);
3431 public function contains($key)
3433 return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
3435 public function toArray()
3437 return $this->_items;
3439 public function offsetExists($offset)
3441 return $this->contains($offset);
3443 public function offsetGet($offset)
3445 return $this->itemAt($offset);
3447 public function offsetSet($offset,$item)
3449 $this->add($offset,$item);
3451 public function offsetUnset($offset)
3453 $this->remove($offset);
3456 class THttpCookieCollection extends TList
3459 public function __construct($owner=null)
3463 public function insertAt($index,$item)
3465 if($item instanceof THttpCookie)
3467 parent::insertAt($index,$item);
3468 if($this->_o instanceof THttpResponse)
3469 $this->_o->addCookie($item);
3472 throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
3474 public function removeAt($index)
3476 $item=parent::removeAt($index);
3477 if($this->_o instanceof THttpResponse)
3478 $this->_o->removeCookie($item);
3481 public function itemAt($index)
3483 if(is_integer($index))
3484 return parent::itemAt($index);
3486 return $this->findCookieByName($index);
3488 public function findCookieByName($name)
3490 foreach($this as $cookie)
3491 if($cookie->getName()===$name)
3496 class THttpCookie extends TComponent
3498 private $_domain='';
3503 private $_secure=false;
3504 private $_httpOnly=false;
3505 public function __construct($name,$value)
3508 $this->_value=$value;
3510 public function getDomain()
3512 return $this->_domain;
3514 public function setDomain($value)
3516 $this->_domain=$value;
3518 public function getExpire()
3520 return $this->_expire;
3522 public function setExpire($value)
3524 $this->_expire=TPropertyValue::ensureInteger($value);
3526 public function getHttpOnly()
3528 return $this->_httpOnly;
3530 public function setHttpOnly($value)
3532 $this->_httpOnly = TPropertyValue::ensureBoolean($value);
3534 public function getName()
3536 return $this->_name;
3538 public function setName($value)
3540 $this->_name=$value;
3542 public function getValue()
3544 return $this->_value;
3546 public function setValue($value)
3548 $this->_value=$value;
3550 public function getPath()
3552 return $this->_path;
3554 public function setPath($value)
3556 $this->_path=$value;
3558 public function getSecure()
3560 return $this->_secure;
3562 public function setSecure($value)
3564 $this->_secure=TPropertyValue::ensureBoolean($value);
3567 class TUri extends TComponent
3569 private static $_defaultPort=array(
3588 public function __construct($uri)
3590 if(($ret=@parse_url($uri))!==false)
3592 $this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
3593 $this->_host=isset($ret['host'])?$ret['host']:'';
3594 $this->_port=isset($ret['port'])?$ret['port']:'';
3595 $this->_user=isset($ret['user'])?$ret['user']:'';
3596 $this->_pass=isset($ret['pass'])?$ret['pass']:'';
3597 $this->_path=isset($ret['path'])?$ret['path']:'';
3598 $this->_query=isset($ret['query'])?$ret['query']:'';
3599 $this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
3604 throw new TInvalidDataValueException('uri_format_invalid',$uri);
3607 public function getUri()
3611 public function getScheme()
3613 return $this->_scheme;
3615 public function getHost()
3617 return $this->_host;
3619 public function getPort()
3621 return $this->_port;
3623 public function getUser()
3625 return $this->_user;
3627 public function getPassword()
3629 return $this->_pass;
3631 public function getPath()
3633 return $this->_path;
3635 public function getQuery()
3637 return $this->_query;
3639 public function getFragment()
3641 return $this->_fragment;
3644 class THttpRequestUrlFormat extends TEnumerable
3648 const HiddenPath='HiddenPath';
3650 class THttpResponseAdapter extends TApplicationComponent
3653 public function __construct($response)
3655 $this->_response=$response;
3657 public function getResponse()
3659 return $this->_response;
3661 public function flushContent()
3663 $this->_response->flushContent();
3665 public function httpRedirect($url)
3667 $this->_response->httpRedirect($url);
3669 public function createNewHtmlWriter($type, $writer)
3671 return $this->_response->createNewHtmlWriter($type,$writer);
3674 class THttpResponse extends TModule implements ITextWriter
3676 const DEFAULT_CONTENTTYPE = 'text/html';
3677 const DEFAULT_CHARSET = 'UTF-8';
3678 private static $HTTP_STATUS_CODES = array(
3679 100 => 'Continue', 101 => 'Switching Protocols',
3680 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
3681 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
3682 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',
3683 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
3685 private $_bufferOutput=true;
3686 private $_initialized=false;
3687 private $_cookies=null;
3688 private $_status=200;
3689 private $_reason='OK';
3690 private $_htmlWriterType='System.Web.UI.THtmlWriter';
3691 private $_contentType=null;
3692 private $_charset='';
3694 private $_httpHeaderSent;
3695 private $_contentTypeHeaderSent;
3696 public function __destruct()
3699 public function setAdapter(THttpResponseAdapter $adapter)
3701 $this->_adapter=$adapter;
3703 public function getAdapter()
3705 return $this->_adapter;
3707 public function getHasAdapter()
3709 return $this->_adapter!==null;
3711 public function init($config)
3713 if($this->_bufferOutput)
3715 $this->_initialized=true;
3716 $this->getApplication()->setResponse($this);
3718 public function getCacheExpire()
3720 return session_cache_expire();
3722 public function setCacheExpire($value)
3724 session_cache_expire(TPropertyValue::ensureInteger($value));
3726 public function getCacheControl()
3728 return session_cache_limiter();
3730 public function setCacheControl($value)
3732 session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
3734 public function setContentType($type)
3736 if ($this->_contentTypeHeaderSent)
3737 throw new Exception('Unable to alter content-type as it has been already sent');
3738 $this->_contentType = $type;
3740 public function getContentType()
3742 return $this->_contentType;
3744 public function getCharset()
3746 return $this->_charset;
3748 public function setCharset($charset)
3750 $this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
3752 public function getBufferOutput()
3754 return $this->_bufferOutput;
3756 public function setBufferOutput($value)
3758 if($this->_initialized)
3759 throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
3761 $this->_bufferOutput=TPropertyValue::ensureBoolean($value);
3763 public function getStatusCode()
3765 return $this->_status;
3767 public function setStatusCode($status, $reason=null)
3769 if ($this->_httpHeaderSent)
3770 throw new Exception('Unable to alter response as HTTP header already sent');
3771 $status=TPropertyValue::ensureInteger($status);
3772 if(isset(self::$HTTP_STATUS_CODES[$status])) {
3773 $this->_reason=self::$HTTP_STATUS_CODES[$status];
3775 if($reason===null || $reason==='') {
3776 throw new TInvalidDataValueException("response_status_reason_missing");
3778 $reason=TPropertyValue::ensureString($reason);
3779 if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
3780 throw new TInvalidDataValueException("response_status_reason_barchars");
3782 $this->_reason=$reason;
3784 $this->_status=$status;
3786 public function getStatusReason() {
3787 return $this->_reason;
3789 public function getCookies()
3791 if($this->_cookies===null)
3792 $this->_cookies=new THttpCookieCollection($this);
3793 return $this->_cookies;
3795 public function write($str)
3797 if (!$this->_bufferOutput and !$this->_httpHeaderSent)
3798 $this->ensureHeadersSent();
3801 public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
3803 static $defaultMimeTypes=array(
3807 'jpg'=>'image/jpeg',
3808 'jpeg'=>'image/jpeg',
3810 'html'=>'text/html',
3811 'js'=>'javascript/js',
3812 'pdf'=>'application/pdf',
3813 'xls'=>'application/vnd.ms-excel',
3815 if($mimeType===null)
3817 $mimeType='text/plain';
3818 if(function_exists('mime_content_type'))
3819 $mimeType=mime_content_type($fileName);
3820 else if(($ext=strrchr($fileName,'.'))!==false)
3822 $ext=substr($ext,1);
3823 if(isset($defaultMimeTypes[$ext]))
3824 $mimeType=$defaultMimeTypes[$ext];
3827 if($clientFileName===null)
3828 $clientFileName=basename($fileName);
3830 $clientFileName=basename($clientFileName);
3831 if($fileSize===null || $fileSize < 0)
3832 $fileSize = ($content===null?filesize($fileName):strlen($content));
3833 $this->sendHttpHeader();
3834 if(is_array($headers))
3836 foreach($headers as $h)
3841 header('Pragma: public');
3842 header('Expires: 0');
3843 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
3844 header("Content-Type: $mimeType");
3845 $this->_contentTypeHeaderSent = true;
3847 header('Content-Length: '.$fileSize);
3848 header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
3849 header('Content-Transfer-Encoding: binary');
3851 readfile($fileName);
3855 public function redirect($url)
3857 if($this->getHasAdapter())
3858 $this->_adapter->httpRedirect($url);
3860 $this->httpRedirect($url);
3862 public function httpRedirect($url)
3864 $this->ensureHeadersSent();
3866 $url=$this->getRequest()->getBaseUrl().$url;
3867 if ($this->_status >= 300 && $this->_status < 400)
3868 header('Location: '.str_replace('&','&',$url), true, $this->_status);
3870 header('Location: '.str_replace('&','&',$url));
3871 if(!$this->getApplication()->getRequestCompleted())
3872 $this->getApplication()->onEndRequest();
3875 public function reload()
3877 $this->redirect($this->getRequest()->getRequestUri());
3879 public function flush($continueBuffering = true)
3881 if($this->getHasAdapter())
3882 $this->_adapter->flushContent($continueBuffering);
3884 $this->flushContent($continueBuffering);
3886 public function ensureHeadersSent()
3888 $this->ensureHttpHeaderSent();
3889 $this->ensureContentTypeHeaderSent();
3891 public function flushContent($continueBuffering = true)
3893 $this->ensureHeadersSent();
3894 if($this->_bufferOutput)
3896 if (ob_get_length()>0)
3898 if (!$continueBuffering)
3900 $this->_bufferOutput = false;
3911 protected function ensureHttpHeaderSent()
3913 if (!$this->_httpHeaderSent)
3914 $this->sendHttpHeader();
3916 protected function sendHttpHeader()
3918 $protocol=$this->getRequest()->getHttpProtocolVersion();
3919 if($this->getRequest()->getHttpProtocolVersion() === null)
3920 $protocol='HTTP/1.1';
3921 $phpSapiName = substr(php_sapi_name(), 0, 3);
3922 $cgi = $phpSapiName == 'cgi' || $phpSapiName == 'fpm';
3923 header(($cgi ? 'Status:' : $protocol).' '.$this->_status.' '.$this->_reason, true, TPropertyValue::ensureInteger($this->_status));
3924 $this->_httpHeaderSent = true;
3926 protected function ensureContentTypeHeaderSent()
3928 if (!$this->_contentTypeHeaderSent)
3929 $this->sendContentTypeHeader();
3931 protected function sendContentTypeHeader()
3933 $contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
3934 $charset=$this->getCharset();
3935 if($charset === false) {
3936 $this->appendHeader('Content-Type: '.$contentType);
3939 if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
3940 $charset=$globalization->getCharset();
3941 if($charset==='') $charset = self::DEFAULT_CHARSET;
3942 $this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
3943 $this->_contentTypeHeaderSent = true;
3945 public function getContents()
3947 return $this->_bufferOutput?ob_get_contents():'';
3949 public function clear()
3951 if($this->_bufferOutput)
3954 public function getHeaders($case=null)
3957 $headers = headers_list();
3958 foreach($headers as $header) {
3959 $tmp = explode(':', $header);
3960 $key = trim(array_shift($tmp));
3961 $value = trim(implode(':', $tmp));
3962 if(isset($result[$key]))
3963 $result[$key] .= ', ' . $value;
3965 $result[$key] = $value;
3968 return array_change_key_case($result, $case);
3971 public function appendHeader($value, $replace=true)
3973 header($value, $replace);
3975 public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
3977 error_log($message,$messageType,$destination,$extraHeaders);
3979 public function addCookie($cookie)
3981 $request=$this->getRequest();
3982 if($request->getEnableCookieValidation())
3984 $value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
3988 $cookie->getExpire(),
3990 $cookie->getDomain(),
3991 $cookie->getSecure(),
3992 $cookie->getHttpOnly()
3998 $cookie->getValue(),
3999 $cookie->getExpire(),
4001 $cookie->getDomain(),
4002 $cookie->getSecure(),
4003 $cookie->getHttpOnly()
4007 public function removeCookie($cookie)
4014 $cookie->getDomain(),
4015 $cookie->getSecure(),
4016 $cookie->getHttpOnly()
4019 public function getHtmlWriterType()
4021 return $this->_htmlWriterType;
4023 public function setHtmlWriterType($value)
4025 $this->_htmlWriterType=$value;
4027 public function createHtmlWriter($type=null)
4030 $type=$this->getHtmlWriterType();
4031 if($this->getHasAdapter())
4032 return $this->_adapter->createNewHtmlWriter($type, $this);
4034 return $this->createNewHtmlWriter($type, $this);
4036 public function createNewHtmlWriter($type, $writer)
4038 return Prado::createComponent($type, $writer);
4041 class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
4043 private $_initialized=false;
4044 private $_started=false;
4045 private $_autoStart=false;
4046 private $_cookie=null;
4048 private $_customStorage=false;
4049 public function getID()
4053 public function setID($value)
4057 public function init($config)
4059 if($this->_autoStart)
4061 $this->_initialized=true;
4062 $this->getApplication()->setSession($this);
4063 register_shutdown_function(array($this, "close"));
4065 public function open()
4067 if(!$this->_started)
4069 if($this->_customStorage)
4070 session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
4071 if($this->_cookie!==null)
4072 session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure(),$this->_cookie->getHttpOnly());
4073 if(ini_get('session.auto_start')!=='1')
4075 $this->_started=true;
4078 public function close()
4082 session_write_close();
4083 $this->_started=false;
4086 public function destroy()
4091 $this->_started=false;
4094 public function regenerate($deleteOld=false)
4096 $old = $this->getSessionID();
4097 session_regenerate_id($deleteOld);
4100 public function getIsStarted()
4102 return $this->_started;
4104 public function getSessionID()
4106 return session_id();
4108 public function setSessionID($value)
4111 throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
4115 public function getSessionName()
4117 return session_name();
4119 public function setSessionName($value)
4122 throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
4123 else if(ctype_alnum($value))
4124 session_name($value);
4126 throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
4128 public function getSavePath()
4130 return session_save_path();
4132 public function setSavePath($value)
4135 throw new TInvalidOperationException('httpsession_savepath_unchangeable');
4136 else if(is_dir($value))
4137 session_save_path($value);
4139 throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
4141 public function getUseCustomStorage()
4143 return $this->_customStorage;
4145 public function setUseCustomStorage($value)
4147 $this->_customStorage=TPropertyValue::ensureBoolean($value);
4149 public function getCookie()
4151 if($this->_cookie===null)
4152 $this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
4153 return $this->_cookie;
4155 public function getCookieMode()
4157 if(ini_get('session.use_cookies')==='0')
4158 return THttpSessionCookieMode::None;
4159 else if(ini_get('session.use_only_cookies')==='0')
4160 return THttpSessionCookieMode::Allow;
4162 return THttpSessionCookieMode::Only;
4164 public function setCookieMode($value)
4167 throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
4170 $value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
4171 if($value===THttpSessionCookieMode::None)
4173 ini_set('session.use_cookies','0');
4174 ini_set('session.use_only_cookies','0');
4176 else if($value===THttpSessionCookieMode::Allow)
4178 ini_set('session.use_cookies','1');
4179 ini_set('session.use_only_cookies','0');
4183 ini_set('session.use_cookies','1');
4184 ini_set('session.use_only_cookies','1');
4185 ini_set('session.use_trans_sid', 0);
4189 public function getAutoStart()
4191 return $this->_autoStart;
4193 public function setAutoStart($value)
4195 if($this->_initialized)
4196 throw new TInvalidOperationException('httpsession_autostart_unchangeable');
4198 $this->_autoStart=TPropertyValue::ensureBoolean($value);
4200 public function getGCProbability()
4202 return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
4204 public function setGCProbability($value)
4207 throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
4210 $value=TPropertyValue::ensureInteger($value);
4211 if($value>=0 && $value<=100)
4213 ini_set('session.gc_probability',$value);
4214 ini_set('session.gc_divisor','100');
4217 throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
4220 public function getUseTransparentSessionID()
4222 return ini_get('session.use_trans_sid')==='1';
4224 public function setUseTransparentSessionID($value)
4227 throw new TInvalidOperationException('httpsession_transid_unchangeable');
4230 $value=TPropertyValue::ensureBoolean($value);
4231 if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
4232 throw new TInvalidOperationException('httpsession_transid_cookieonly');
4233 ini_set('session.use_trans_sid',$value?'1':'0');
4236 public function getTimeout()
4238 return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
4240 public function setTimeout($value)
4243 throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
4245 ini_set('session.gc_maxlifetime',$value);
4247 public function _open($savePath,$sessionName)
4251 public function _close()
4255 public function _read($id)
4259 public function _write($id,$data)
4263 public function _destroy($id)
4267 public function _gc($maxLifetime)
4271 public function getIterator()
4273 return new TSessionIterator;
4275 public function getCount()
4277 return count($_SESSION);
4279 public function count()
4281 return $this->getCount();
4283 public function getKeys()
4285 return array_keys($_SESSION);
4287 public function itemAt($key)
4289 return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
4291 public function add($key,$value)
4293 $_SESSION[$key]=$value;
4295 public function remove($key)
4297 if(isset($_SESSION[$key]))
4299 $value=$_SESSION[$key];
4300 unset($_SESSION[$key]);
4306 public function clear()
4308 foreach(array_keys($_SESSION) as $key)
4309 unset($_SESSION[$key]);
4311 public function contains($key)
4313 return isset($_SESSION[$key]);
4315 public function toArray()
4319 public function offsetExists($offset)
4321 return isset($_SESSION[$offset]);
4323 public function offsetGet($offset)
4325 return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
4327 public function offsetSet($offset,$item)
4329 $_SESSION[$offset]=$item;
4331 public function offsetUnset($offset)
4333 unset($_SESSION[$offset]);
4336 class TSessionIterator implements Iterator
4340 public function __construct()
4342 $this->_keys=array_keys($_SESSION);
4344 public function rewind()
4346 $this->_key=reset($this->_keys);
4348 public function key()
4352 public function current()
4354 return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
4356 public function next()
4360 $this->_key=next($this->_keys);
4362 while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
4364 public function valid()
4366 return $this->_key!==false;
4369 class THttpSessionCookieMode extends TEnumerable
4372 const Allow='Allow';
4375 Prado::using('System.Web.UI.WebControls.*');
4376 class TAttributeCollection extends TMap
4378 private $_caseSensitive=false;
4379 protected function _getZappableSleepProps(&$exprops)
4381 parent::_getZappableSleepProps($exprops);
4382 if ($this->_caseSensitive===false)
4383 $exprops[] = "\0TAttributeCollection\0_caseSensitive";
4385 public function __get($name)
4387 return $this->contains($name)?$this->itemAt($name):parent::__get($name);
4389 public function __set($name,$value)
4391 $this->add($name,$value);
4393 public function getCaseSensitive()
4395 return $this->_caseSensitive;
4397 public function setCaseSensitive($value)
4399 $this->_caseSensitive=TPropertyValue::ensureBoolean($value);
4401 public function itemAt($key)
4403 return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
4405 public function add($key,$value)
4407 parent::add($this->_caseSensitive?$key:strtolower($key),$value);
4409 public function remove($key)
4411 return parent::remove($this->_caseSensitive?$key:strtolower($key));
4413 public function contains($key)
4415 return parent::contains($this->_caseSensitive?$key:strtolower($key));
4417 public function hasProperty($name)
4419 return $this->contains($name) || parent::canGetProperty($name) || parent::canSetProperty($name);
4421 public function canGetProperty($name)
4423 return $this->contains($name) || parent::canGetProperty($name);
4425 public function canSetProperty($name)
4430 class TControlAdapter extends TApplicationComponent
4432 protected $_control;
4433 public function __construct($control)
4435 $this->_control=$control;
4437 public function getControl()
4439 return $this->_control;
4441 public function getPage()
4443 return $this->_control?$this->_control->getPage():null;
4445 public function createChildControls()
4447 $this->_control->createChildControls();
4449 public function loadState()
4451 $this->_control->loadState();
4453 public function saveState()
4455 $this->_control->saveState();
4457 public function onInit($param)
4459 $this->_control->onInit($param);
4461 public function onLoad($param)
4463 $this->_control->onLoad($param);
4465 public function onPreRender($param)
4467 $this->_control->onPreRender($param);
4469 public function onUnload($param)
4471 $this->_control->onUnload($param);
4473 public function render($writer)
4475 $this->_control->render($writer);
4477 public function renderChildren($writer)
4479 $this->_control->renderChildren($writer);
4482 class TControl extends TApplicationComponent implements IRenderable, IBindable
4484 const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
4485 const ID_SEPARATOR='$';
4486 const CLIENT_ID_SEPARATOR='_';
4487 const AUTOMATIC_ID_PREFIX='ctl';
4488 const CS_CONSTRUCTED=0;
4489 const CS_CHILD_INITIALIZED=1;
4490 const CS_INITIALIZED=2;
4491 const CS_STATE_LOADED=3;
4493 const CS_PRERENDERED=5;
4494 const IS_ID_SET=0x01;
4495 const IS_DISABLE_VIEWSTATE=0x02;
4496 const IS_SKIN_APPLIED=0x04;
4497 const IS_STYLESHEET_APPLIED=0x08;
4498 const IS_DISABLE_THEMING=0x10;
4499 const IS_CHILD_CREATED=0x20;
4500 const IS_CREATING_CHILD=0x40;
4501 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;
4506 private $_namingContainer;
4507 private $_tplControl;
4508 private $_viewState=array();
4509 private $_tempState=array();
4510 private $_trackViewState=true;
4513 private $_rf=array();
4514 public function __get($name)
4516 if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
4517 return $this->_rf[self::RF_NAMED_OBJECTS][$name];
4519 return parent::__get($name);
4521 public function __isset($name) {
4522 if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) {
4525 return parent::__isset($name);
4528 public function getHasAdapter()
4530 return isset($this->_rf[self::RF_ADAPTER]);
4532 public function getAdapter()
4534 return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
4536 public function setAdapter(TControlAdapter $adapter)
4538 $this->_rf[self::RF_ADAPTER]=$adapter;
4540 public function getParent()
4542 return $this->_parent;
4544 public function getNamingContainer()
4546 if(!$this->_namingContainer && $this->_parent)
4548 if($this->_parent instanceof INamingContainer)
4549 $this->_namingContainer=$this->_parent;
4551 $this->_namingContainer=$this->_parent->getNamingContainer();
4553 return $this->_namingContainer;
4555 public function getPage()
4560 $this->_page=$this->_parent->getPage();
4561 else if($this->_tplControl)
4562 $this->_page=$this->_tplControl->getPage();
4564 return $this->_page;
4566 public function setPage($page)
4570 public function setTemplateControl($control)
4572 $this->_tplControl=$control;
4574 public function getTemplateControl()
4576 if(!$this->_tplControl && $this->_parent)
4577 $this->_tplControl=$this->_parent->getTemplateControl();
4578 return $this->_tplControl;
4580 public function getSourceTemplateControl()
4583 while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
4585 if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
4588 return $this->getPage();
4590 protected function getControlStage()
4592 return $this->_stage;
4594 protected function setControlStage($value)
4596 $this->_stage=$value;
4598 public function getID($hideAutoID=true)
4601 return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
4605 public function setID($id)
4607 if(!preg_match(self::ID_FORMAT,$id))
4608 throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
4610 $this->_flags |= self::IS_ID_SET;
4611 $this->clearCachedUniqueID($this instanceof INamingContainer);
4612 if($this->_namingContainer)
4613 $this->_namingContainer->clearNameTable();
4615 public function getUniqueID()
4617 if($this->_uid==='' || $this->_uid===null) {
4618 $this->_uid=''; if($namingContainer=$this->getNamingContainer())
4620 if($this->getPage()===$namingContainer)
4621 return ($this->_uid=$this->_id);
4622 else if(($prefix=$namingContainer->getUniqueID())==='')
4625 return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
4627 else return $this->_id;
4632 public function focus()
4634 $this->getPage()->setFocus($this);
4636 public function getClientID()
4638 return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4640 public static function convertUniqueIdToClientId($uniqueID)
4642 return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4644 public function getSkinID()
4646 return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
4648 public function setSkinID($value)
4650 if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
4651 throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
4653 $this->_rf[self::RF_SKIN_ID]=$value;
4655 public function getIsSkinApplied()
4657 return ($this->_flags & self::IS_SKIN_APPLIED);
4659 public function getEnableTheming()
4661 if($this->_flags & self::IS_DISABLE_THEMING)
4664 return $this->_parent?$this->_parent->getEnableTheming():true;
4666 public function setEnableTheming($value)
4668 if($this->_stage>=self::CS_CHILD_INITIALIZED)
4669 throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
4670 else if(TPropertyValue::ensureBoolean($value))
4671 $this->_flags &= ~self::IS_DISABLE_THEMING;
4673 $this->_flags |= self::IS_DISABLE_THEMING;
4675 public function getCustomData()
4677 return $this->getViewState('CustomData',null);
4679 public function setCustomData($value)
4681 $this->setViewState('CustomData',$value,null);
4683 public function getHasControls()
4685 return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
4687 public function getControls()
4689 if(!isset($this->_rf[self::RF_CONTROLS]))
4690 $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
4691 return $this->_rf[self::RF_CONTROLS];
4693 protected function createControlCollection()
4695 return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
4697 public function getVisible($checkParents=true)
4701 for($control=$this;$control;$control=$control->_parent)
4702 if(!$control->getVisible(false))
4707 return $this->getViewState('Visible',true);
4709 public function setVisible($value)
4711 $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
4713 public function getEnabled($checkParents=false)
4717 for($control=$this;$control;$control=$control->_parent)
4718 if(!$control->getViewState('Enabled',true))
4723 return $this->getViewState('Enabled',true);
4725 public function setEnabled($value)
4727 $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
4729 public function getHasAttributes()
4731 if($attributes=$this->getViewState('Attributes',null))
4732 return $attributes->getCount()>0;
4736 public function getAttributes()
4738 if($attributes=$this->getViewState('Attributes',null))
4742 $attributes=new TAttributeCollection;
4743 $this->setViewState('Attributes',$attributes,null);
4747 public function hasAttribute($name)
4749 if($attributes=$this->getViewState('Attributes',null))
4750 return $attributes->contains($name);
4754 public function getAttribute($name)
4756 if($attributes=$this->getViewState('Attributes',null))
4757 return $attributes->itemAt($name);
4761 public function setAttribute($name,$value)
4763 $this->getAttributes()->add($name,$value);
4765 public function removeAttribute($name)
4767 if($attributes=$this->getViewState('Attributes',null))
4768 return $attributes->remove($name);
4772 public function getEnableViewState($checkParents=false)
4776 for($control=$this;$control!==null;$control=$control->getParent())
4777 if($control->_flags & self::IS_DISABLE_VIEWSTATE)
4782 return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
4784 public function setEnableViewState($value)
4786 if(TPropertyValue::ensureBoolean($value))
4787 $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
4789 $this->_flags |= self::IS_DISABLE_VIEWSTATE;
4791 protected function getControlState($key,$defaultValue=null)
4793 return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
4795 protected function setControlState($key,$value,$defaultValue=null)
4797 if($value===$defaultValue)
4798 unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4800 $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
4802 protected function clearControlState($key)
4804 unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4806 public function trackViewState($enabled)
4808 $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
4810 public function getViewState($key,$defaultValue=null)
4812 if(isset($this->_viewState[$key]))
4813 return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
4814 else if(isset($this->_tempState[$key]))
4816 if(is_object($this->_tempState[$key]) && $this->_trackViewState)
4817 $this->_viewState[$key]=$this->_tempState[$key];
4818 return $this->_tempState[$key];
4821 return $defaultValue;
4823 public function setViewState($key,$value,$defaultValue=null)
4825 if($this->_trackViewState)
4827 unset($this->_tempState[$key]);
4828 $this->_viewState[$key]=$value;
4832 unset($this->_viewState[$key]);
4833 if($value===$defaultValue)
4834 unset($this->_tempState[$key]);
4836 $this->_tempState[$key]=$value;
4839 public function clearViewState($key)
4841 unset($this->_viewState[$key]);
4842 unset($this->_tempState[$key]);
4844 public function bindProperty($name,$expression)
4846 $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
4848 public function unbindProperty($name)
4850 unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
4852 public function autoBindProperty($name,$expression)
4854 $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
4856 public function dataBind()
4858 $this->dataBindProperties();
4859 $this->onDataBinding(null);
4860 $this->dataBindChildren();
4862 protected function dataBindProperties()
4864 if(isset($this->_rf[self::RF_DATA_BINDINGS]))
4866 if(($context=$this->getTemplateControl())===null)
4868 foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
4869 $this->setSubProperty($property,$context->evaluateExpression($expression));
4872 protected function autoDataBindProperties()
4874 if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
4876 if(($context=$this->getTemplateControl())===null)
4878 foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
4879 $this->setSubProperty($property,$context->evaluateExpression($expression));
4882 protected function dataBindChildren()
4884 if(isset($this->_rf[self::RF_CONTROLS]))
4886 foreach($this->_rf[self::RF_CONTROLS] as $control)
4887 if($control instanceof IBindable)
4888 $control->dataBind();
4891 final protected function getChildControlsCreated()
4893 return ($this->_flags & self::IS_CHILD_CREATED)!==0;
4895 final protected function setChildControlsCreated($value)
4898 $this->_flags |= self::IS_CHILD_CREATED;
4901 if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
4902 $this->getControls()->clear();
4903 $this->_flags &= ~self::IS_CHILD_CREATED;
4906 public function ensureChildControls()
4908 if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
4912 $this->_flags |= self::IS_CREATING_CHILD;
4913 if(isset($this->_rf[self::RF_ADAPTER]))
4914 $this->_rf[self::RF_ADAPTER]->createChildControls();
4916 $this->createChildControls();
4917 $this->_flags &= ~self::IS_CREATING_CHILD;
4918 $this->_flags |= self::IS_CHILD_CREATED;
4922 $this->_flags &= ~self::IS_CREATING_CHILD;
4923 $this->_flags |= self::IS_CHILD_CREATED;
4928 public function createChildControls()
4931 public function findControl($id)
4933 $id=strtr($id,'.',self::ID_SEPARATOR);
4934 $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
4935 if(!$container || !$container->getHasControls())
4937 if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
4939 $container->_rf[self::RF_NAMED_CONTROLS]=array();
4940 $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
4942 if(($pos=strpos($id,self::ID_SEPARATOR))===false)
4943 return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
4946 $cid=substr($id,0,$pos);
4947 $sid=substr($id,$pos+1);
4948 if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
4949 return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
4954 public function findControlsByType($type,$strict=true)
4957 if($this->getHasControls())
4959 foreach($this->_rf[self::RF_CONTROLS] as $control)
4961 if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
4962 $controls[]=$control;
4963 if(($control instanceof TControl) && $control->getHasControls())
4964 $controls=array_merge($controls,$control->findControlsByType($type,$strict));
4969 public function findControlsByID($id)
4972 if($this->getHasControls())
4974 foreach($this->_rf[self::RF_CONTROLS] as $control)
4976 if($control instanceof TControl)
4978 if($control->_id===$id)
4979 $controls[]=$control;
4980 $controls=array_merge($controls,$control->findControlsByID($id));
4986 public function clearNamingContainer()
4988 unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
4989 $this->clearNameTable();
4991 public function registerObject($name,$object)
4993 if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
4994 throw new TInvalidOperationException('control_object_reregistered',$name);
4995 $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
4997 public function unregisterObject($name)
4999 unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5001 public function isObjectRegistered($name)
5003 return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5005 public function getHasChildInitialized()
5007 return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
5009 public function getHasInitialized()
5011 return $this->getControlStage() >= self::CS_INITIALIZED;
5013 public function getHasLoadedPostData()
5015 return $this->getControlStage() >= self::CS_STATE_LOADED;
5017 public function getHasLoaded()
5019 return $this->getControlStage() >= self::CS_LOADED;
5021 public function getHasPreRendered()
5023 return $this->getControlStage() >= self::CS_PRERENDERED;
5025 public function getRegisteredObject($name)
5027 return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
5029 public function getAllowChildControls()
5033 public function addParsedObject($object)
5035 $this->getControls()->add($object);
5037 final protected function clearChildState()
5039 unset($this->_rf[self::RF_CHILD_STATE]);
5041 final protected function isDescendentOf($ancestor)
5044 while($control!==$ancestor && $control->_parent)
5045 $control=$control->_parent;
5046 return $control===$ancestor;
5048 public function addedControl($control)
5050 if($control->_parent)
5051 $control->_parent->getControls()->remove($control);
5052 $control->_parent=$this;
5053 $control->_page=$this->getPage();
5054 $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
5055 if($namingContainer)
5057 $control->_namingContainer=$namingContainer;
5058 if($control->_id==='')
5059 $control->generateAutomaticID();
5061 $namingContainer->clearNameTable();
5062 $control->clearCachedUniqueID($control instanceof INamingContainer);
5064 if($this->_stage>=self::CS_CHILD_INITIALIZED)
5066 $control->initRecursive($namingContainer);
5067 if($this->_stage>=self::CS_STATE_LOADED)
5069 if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
5071 $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
5072 unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
5076 $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
5077 if($this->_stage>=self::CS_LOADED)
5079 $control->loadRecursive();
5080 if($this->_stage>=self::CS_PRERENDERED)
5081 $control->preRenderRecursive();
5086 public function removedControl($control)
5088 if($this->_namingContainer)
5089 $this->_namingContainer->clearNameTable();
5090 $control->unloadRecursive();
5091 $control->_parent=null;
5092 $control->_page=null;
5093 $control->_namingContainer=null;
5094 $control->_tplControl=null;
5095 if(!($control->_flags & self::IS_ID_SET))
5098 unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
5099 $control->clearCachedUniqueID(true);
5101 protected function initRecursive($namingContainer=null)
5103 $this->ensureChildControls();
5104 if($this->getHasControls())
5106 if($this instanceof INamingContainer)
5107 $namingContainer=$this;
5108 $page=$this->getPage();
5109 foreach($this->_rf[self::RF_CONTROLS] as $control)
5111 if($control instanceof TControl)
5113 $control->_namingContainer=$namingContainer;
5114 $control->_page=$page;
5115 if($control->_id==='' && $namingContainer)
5116 $control->generateAutomaticID();
5117 $control->initRecursive($namingContainer);
5121 if($this->_stage<self::CS_INITIALIZED)
5123 $this->_stage=self::CS_CHILD_INITIALIZED;
5124 if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
5126 $page->applyControlSkin($this);
5127 $this->_flags |= self::IS_SKIN_APPLIED;
5129 if(isset($this->_rf[self::RF_ADAPTER]))
5130 $this->_rf[self::RF_ADAPTER]->onInit(null);
5132 $this->onInit(null);
5133 $this->_stage=self::CS_INITIALIZED;
5136 protected function loadRecursive()
5138 if($this->_stage<self::CS_LOADED)
5140 if(isset($this->_rf[self::RF_ADAPTER]))
5141 $this->_rf[self::RF_ADAPTER]->onLoad(null);
5143 $this->onLoad(null);
5145 if($this->getHasControls())
5147 foreach($this->_rf[self::RF_CONTROLS] as $control)
5149 if($control instanceof TControl)
5150 $control->loadRecursive();
5153 if($this->_stage<self::CS_LOADED)
5154 $this->_stage=self::CS_LOADED;
5156 protected function preRenderRecursive()
5158 $this->autoDataBindProperties();
5159 if($this->getVisible(false))
5161 if(isset($this->_rf[self::RF_ADAPTER]))
5162 $this->_rf[self::RF_ADAPTER]->onPreRender(null);
5164 $this->onPreRender(null);
5165 if($this->getHasControls())
5167 foreach($this->_rf[self::RF_CONTROLS] as $control)
5169 if($control instanceof TControl)
5170 $control->preRenderRecursive();
5171 else if($control instanceof TCompositeLiteral)
5172 $control->evaluateDynamicContent();
5176 $this->_stage=self::CS_PRERENDERED;
5178 protected function unloadRecursive()
5180 if(!($this->_flags & self::IS_ID_SET))
5182 if($this->getHasControls())
5184 foreach($this->_rf[self::RF_CONTROLS] as $control)
5185 if($control instanceof TControl)
5186 $control->unloadRecursive();
5188 if(isset($this->_rf[self::RF_ADAPTER]))
5189 $this->_rf[self::RF_ADAPTER]->onUnload(null);
5191 $this->onUnload(null);
5193 public function onInit($param)
5195 $this->raiseEvent('OnInit',$this,$param);
5197 public function onLoad($param)
5199 $this->raiseEvent('OnLoad',$this,$param);
5201 public function onDataBinding($param)
5203 $this->raiseEvent('OnDataBinding',$this,$param);
5205 public function onUnload($param)
5207 $this->raiseEvent('OnUnload',$this,$param);
5209 public function onPreRender($param)
5211 $this->raiseEvent('OnPreRender',$this,$param);
5213 protected function raiseBubbleEvent($sender,$param)
5216 while($control=$control->_parent)
5218 if($control->bubbleEvent($sender,$param))
5222 public function bubbleEvent($sender,$param)
5226 public function broadcastEvent($name,$sender,$param)
5228 $rootControl=(($page=$this->getPage())===null)?$this:$page;
5229 $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
5231 private function broadcastEventInternal($name,$sender,$param)
5233 if($this->hasEvent($name))
5234 $this->raiseEvent($name,$sender,$param->getParameter());
5235 if($this instanceof IBroadcastEventReceiver)
5236 $this->broadcastEventReceived($sender,$param);
5237 if($this->getHasControls())
5239 foreach($this->_rf[self::RF_CONTROLS] as $control)
5241 if($control instanceof TControl)
5242 $control->broadcastEventInternal($name,$sender,$param);
5246 protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
5248 if($preCallback!==null)
5249 call_user_func($preCallback,$this,$param);
5250 if($this->getHasControls())
5252 foreach($this->_rf[self::RF_CONTROLS] as $control)
5254 if($control instanceof TControl)
5256 $control->traverseChildControls($param,$preCallback,$postCallback);
5260 if($postCallback!==null)
5261 call_user_func($postCallback,$this,$param);
5263 public function renderControl($writer)
5265 if($this instanceof IActiveControl || $this->getVisible(false))
5267 if(isset($this->_rf[self::RF_ADAPTER]))
5268 $this->_rf[self::RF_ADAPTER]->render($writer);
5270 $this->render($writer);
5273 public function render($writer)
5275 $this->renderChildren($writer);
5277 public function renderChildren($writer)
5279 if($this->getHasControls())
5281 foreach($this->_rf[self::RF_CONTROLS] as $control)
5283 if(is_string($control))
5284 $writer->write($control);
5285 else if($control instanceof TControl)
5286 $control->renderControl($writer);
5287 else if($control instanceof IRenderable)
5288 $control->render($writer);
5292 public function saveState()
5295 public function loadState()
5298 protected function loadStateRecursive(&$state,$needViewState=true)
5300 if(is_array($state))
5302 $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5303 if(isset($state[1]))
5305 $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
5309 unset($this->_rf[self::RF_CONTROLSTATE]);
5312 if(isset($state[0]))
5313 $this->_viewState=&$state[0];
5315 $this->_viewState=array();
5318 if($this->getHasControls())
5320 foreach($this->_rf[self::RF_CONTROLS] as $control)
5322 if($control instanceof TControl)
5324 if(isset($state[$control->_id]))
5326 $control->loadStateRecursive($state[$control->_id],$needViewState);
5327 unset($state[$control->_id]);
5333 $this->_rf[self::RF_CHILD_STATE]=&$state;
5335 $this->_stage=self::CS_STATE_LOADED;
5336 if(isset($this->_rf[self::RF_ADAPTER]))
5337 $this->_rf[self::RF_ADAPTER]->loadState();
5341 protected function &saveStateRecursive($needViewState=true)
5343 if(isset($this->_rf[self::RF_ADAPTER]))
5344 $this->_rf[self::RF_ADAPTER]->saveState();
5347 $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5349 if($this->getHasControls())
5351 foreach($this->_rf[self::RF_CONTROLS] as $control)
5353 if($control instanceof TControl)
5355 if(count($tmp = &$control->saveStateRecursive($needViewState)))
5356 $state[$control->_id]=$tmp;
5360 if($needViewState && !empty($this->_viewState))
5361 $state[0]=&$this->_viewState;
5362 if(isset($this->_rf[self::RF_CONTROLSTATE]))
5363 $state[1]=&$this->_rf[self::RF_CONTROLSTATE];
5366 public function applyStyleSheetSkin($page)
5368 if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
5370 $page->applyControlStyleSheet($this);
5371 $this->_flags |= self::IS_STYLESHEET_APPLIED;
5373 else if($this->_flags & self::IS_STYLESHEET_APPLIED)
5374 throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
5376 private function clearCachedUniqueID($recursive)
5378 if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
5380 foreach($this->_rf[self::RF_CONTROLS] as $control)
5381 if($control instanceof TControl)
5382 $control->clearCachedUniqueID($recursive);
5386 private function generateAutomaticID()
5388 $this->_flags &= ~self::IS_ID_SET;
5389 if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
5390 $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
5391 $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
5392 $this->_id=self::AUTOMATIC_ID_PREFIX . $id;
5393 $this->_namingContainer->clearNameTable();
5395 private function clearNameTable()
5397 unset($this->_rf[self::RF_NAMED_CONTROLS]);
5399 private function fillNameTable($container,$controls)
5401 foreach($controls as $control)
5403 if($control instanceof TControl)
5405 if($control->_id!=='')
5407 if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
5408 throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
5410 $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
5412 if(!($control instanceof INamingContainer) && $control->getHasControls())
5413 $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
5418 class TControlCollection extends TList
5421 public function __construct(TControl $owner,$readOnly=false)
5424 parent::__construct(null,$readOnly);
5426 protected function getOwner()
5430 public function insertAt($index,$item)
5432 if($item instanceof TControl)
5434 parent::insertAt($index,$item);
5435 $this->_o->addedControl($item);
5437 else if(is_string($item) || ($item instanceof IRenderable))
5438 parent::insertAt($index,$item);
5440 throw new TInvalidDataTypeException('controlcollection_control_required');
5442 public function removeAt($index)
5444 $item=parent::removeAt($index);
5445 if($item instanceof TControl)
5446 $this->_o->removedControl($item);
5449 public function clear()
5452 if($this->_o instanceof INamingContainer)
5453 $this->_o->clearNamingContainer();
5456 class TEmptyControlCollection extends TControlCollection
5458 public function __construct(TControl $owner)
5460 parent::__construct($owner,true);
5462 public function insertAt($index,$item)
5464 if(!is_string($item)) parent::insertAt($index,$item); }
5466 interface INamingContainer
5469 interface IPostBackEventHandler
5471 public function raisePostBackEvent($param);
5473 interface IPostBackDataHandler
5475 public function loadPostData($key,$values);
5476 public function raisePostDataChangedEvent();
5477 public function getDataChanged();
5479 interface IValidator
5481 public function validate();
5482 public function getIsValid();
5483 public function setIsValid($value);
5484 public function getErrorMessage();
5485 public function setErrorMessage($value);
5487 interface IValidatable
5489 public function getValidationPropertyValue();
5490 public function getIsValid();
5491 public function setIsValid($value);
5493 interface IBroadcastEventReceiver
5495 public function broadcastEventReceived($sender,$param);
5499 public function applySkin($control);
5503 public function instantiateIn($parent);
5505 interface IButtonControl
5507 public function getText();
5508 public function setText($value);
5509 public function getCausesValidation();
5510 public function setCausesValidation($value);
5511 public function getCommandName();
5512 public function setCommandName($value);
5513 public function getCommandParameter();
5514 public function setCommandParameter($value);
5515 public function getValidationGroup();
5516 public function setValidationGroup($value);
5517 public function onClick($param);
5518 public function onCommand($param);
5519 public function setIsDefaultButton($value);
5520 public function getIsDefaultButton();
5522 interface ISurroundable
5524 public function getSurroundingTag();
5525 public function getSurroundingTagID();
5527 class TBroadcastEventParameter extends TEventParameter
5531 public function __construct($name='',$parameter=null)
5534 $this->_param=$parameter;
5536 public function getName()
5538 return $this->_name;
5540 public function setName($value)
5542 $this->_name=$value;
5544 public function getParameter()
5546 return $this->_param;
5548 public function setParameter($value)
5550 $this->_param=$value;
5553 class TCommandEventParameter extends TEventParameter
5557 public function __construct($name='',$parameter='')
5560 $this->_param=$parameter;
5562 public function getCommandName()
5564 return $this->_name;
5566 public function getCommandParameter()
5568 return $this->_param;
5571 class TCompositeLiteral extends TComponent implements IRenderable, IBindable
5573 const TYPE_EXPRESSION=0;
5574 const TYPE_STATEMENTS=1;
5575 const TYPE_DATABINDING=2;
5576 private $_container=null;
5577 private $_items=array();
5578 private $_expressions=array();
5579 private $_statements=array();
5580 private $_bindings=array();
5581 public function __construct($items)
5583 $this->_items=array();
5584 $this->_expressions=array();
5585 $this->_statements=array();
5586 foreach($items as $id=>$item)
5590 if($item[0]===self::TYPE_EXPRESSION)
5591 $this->_expressions[$id]=$item[1];
5592 else if($item[0]===self::TYPE_STATEMENTS)
5593 $this->_statements[$id]=$item[1];
5594 else if($item[0]===self::TYPE_DATABINDING)
5595 $this->_bindings[$id]=$item[1];
5596 $this->_items[$id]='';
5599 $this->_items[$id]=$item;
5602 public function getContainer()
5604 return $this->_container;
5606 public function setContainer(TComponent $value)
5608 $this->_container=$value;
5610 public function evaluateDynamicContent()
5612 $context=$this->_container===null?$this:$this->_container;
5613 foreach($this->_expressions as $id=>$expression)
5614 $this->_items[$id]=$context->evaluateExpression($expression);
5615 foreach($this->_statements as $id=>$statement)
5616 $this->_items[$id]=$context->evaluateStatements($statement);
5618 public function dataBind()
5620 $context=$this->_container===null?$this:$this->_container;
5621 foreach($this->_bindings as $id=>$binding)
5622 $this->_items[$id]=$context->evaluateExpression($binding);
5624 public function render($writer)
5626 $writer->write(implode('',$this->_items));
5629 class TFont extends TComponent
5632 const IS_ITALIC=0x02;
5633 const IS_OVERLINE=0x04;
5634 const IS_STRIKEOUT=0x08;
5635 const IS_UNDERLINE=0x10;
5636 const IS_SET_BOLD=0x01000;
5637 const IS_SET_ITALIC=0x02000;
5638 const IS_SET_OVERLINE=0x04000;
5639 const IS_SET_STRIKEOUT=0x08000;
5640 const IS_SET_UNDERLINE=0x10000;
5641 const IS_SET_SIZE=0x20000;
5642 const IS_SET_NAME=0x40000;
5646 protected function _getZappableSleepProps(&$exprops)
5648 parent::_getZappableSleepProps($exprops);
5649 if ($this->_flags===0)
5650 $exprops[] = "\0TFont\0_flags";
5651 if ($this->_name==='')
5652 $exprops[] = "\0TFont\0_name";
5653 if ($this->_size==='')
5654 $exprops[] = "\0TFont\0_size";
5656 public function getBold()
5658 return ($this->_flags & self::IS_BOLD)!==0;
5660 public function setBold($value)
5662 $this->_flags |= self::IS_SET_BOLD;
5663 if(TPropertyValue::ensureBoolean($value))
5664 $this->_flags |= self::IS_BOLD;
5666 $this->_flags &= ~self::IS_BOLD;
5668 public function getItalic()
5670 return ($this->_flags & self::IS_ITALIC)!==0;
5672 public function setItalic($value)
5674 $this->_flags |= self::IS_SET_ITALIC;
5675 if(TPropertyValue::ensureBoolean($value))
5676 $this->_flags |= self::IS_ITALIC;
5678 $this->_flags &= ~self::IS_ITALIC;
5680 public function getOverline()
5682 return ($this->_flags & self::IS_OVERLINE)!==0;
5684 public function setOverline($value)
5686 $this->_flags |= self::IS_SET_OVERLINE;
5687 if(TPropertyValue::ensureBoolean($value))
5688 $this->_flags |= self::IS_OVERLINE;
5690 $this->_flags &= ~self::IS_OVERLINE;
5692 public function getSize()
5694 return $this->_size;
5696 public function setSize($value)
5698 $this->_flags |= self::IS_SET_SIZE;
5699 $this->_size=$value;
5701 public function getStrikeout()
5703 return ($this->_flags & self::IS_STRIKEOUT)!==0;
5705 public function setStrikeout($value)
5707 $this->_flags |= self::IS_SET_STRIKEOUT;
5708 if(TPropertyValue::ensureBoolean($value))
5709 $this->_flags |= self::IS_STRIKEOUT;
5711 $this->_flags &= ~self::IS_STRIKEOUT;
5713 public function getUnderline()
5715 return ($this->_flags & self::IS_UNDERLINE)!==0;
5717 public function setUnderline($value)
5719 $this->_flags |= self::IS_SET_UNDERLINE;
5720 if(TPropertyValue::ensureBoolean($value))
5721 $this->_flags |= self::IS_UNDERLINE;
5723 $this->_flags &= ~self::IS_UNDERLINE;
5725 public function getName()
5727 return $this->_name;
5729 public function setName($value)
5731 $this->_flags |= self::IS_SET_NAME;
5732 $this->_name=$value;
5734 public function getIsEmpty()
5736 return !$this->_flags;
5738 public function reset()
5744 public function mergeWith($font)
5746 if($font===null || $font->_flags===0)
5748 if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
5749 $this->setBold($font->getBold());
5750 if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
5751 $this->setItalic($font->getItalic());
5752 if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
5753 $this->setOverline($font->getOverline());
5754 if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
5755 $this->setStrikeout($font->getStrikeout());
5756 if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
5757 $this->setUnderline($font->getUnderline());
5758 if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
5759 $this->setSize($font->getSize());
5760 if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
5761 $this->setName($font->getName());
5763 public function copyFrom($font)
5765 if($font===null || $font->_flags===0)
5767 if($font->_flags & self::IS_SET_BOLD)
5768 $this->setBold($font->getBold());
5769 if($font->_flags & self::IS_SET_ITALIC)
5770 $this->setItalic($font->getItalic());
5771 if($font->_flags & self::IS_SET_OVERLINE)
5772 $this->setOverline($font->getOverline());
5773 if($font->_flags & self::IS_SET_STRIKEOUT)
5774 $this->setStrikeout($font->getStrikeout());
5775 if($font->_flags & self::IS_SET_UNDERLINE)
5776 $this->setUnderline($font->getUnderline());
5777 if($font->_flags & self::IS_SET_SIZE)
5778 $this->setSize($font->getSize());
5779 if($font->_flags & self::IS_SET_NAME)
5780 $this->setName($font->getName());
5782 public function toString()
5784 if($this->_flags===0)
5787 if($this->_flags & self::IS_SET_BOLD)
5788 $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
5789 if($this->_flags & self::IS_SET_ITALIC)
5790 $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
5792 if($this->_flags & self::IS_UNDERLINE)
5793 $textDec.='underline';
5794 if($this->_flags & self::IS_OVERLINE)
5795 $textDec.=' overline';
5796 if($this->_flags & self::IS_STRIKEOUT)
5797 $textDec.=' line-through';
5798 $textDec=ltrim($textDec);
5800 $str.='text-decoration:'.$textDec.';';
5801 if($this->_size!=='')
5802 $str.='font-size:'.$this->_size.';';
5803 if($this->_name!=='')
5804 $str.='font-family:'.$this->_name.';';
5807 public function addAttributesToRender($writer)
5809 if($this->_flags===0)
5811 if($this->_flags & self::IS_SET_BOLD)
5812 $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
5813 if($this->_flags & self::IS_SET_ITALIC)
5814 $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
5816 if($this->_flags & self::IS_UNDERLINE)
5817 $textDec.='underline';
5818 if($this->_flags & self::IS_OVERLINE)
5819 $textDec.=' overline';
5820 if($this->_flags & self::IS_STRIKEOUT)
5821 $textDec.=' line-through';
5822 $textDec=ltrim($textDec);
5824 $writer->addStyleAttribute('text-decoration',$textDec);
5825 if($this->_size!=='')
5826 $writer->addStyleAttribute('font-size',$this->_size);
5827 if($this->_name!=='')
5828 $writer->addStyleAttribute('font-family',$this->_name);
5831 class TStyle extends TComponent
5833 private $_fields=array();
5834 private $_font=null;
5835 private $_class=null;
5836 private $_customStyle=null;
5837 private $_displayStyle='Fixed';
5838 protected function _getZappableSleepProps(&$exprops)
5840 parent::_getZappableSleepProps($exprops);
5841 if ($this->_fields===array())
5842 $exprops[] = "\0TStyle\0_fields";
5843 if($this->_font===null)
5844 $exprops[] = "\0TStyle\0_font";
5845 if($this->_class===null)
5846 $exprops[] = "\0TStyle\0_class";
5847 if ($this->_customStyle===null)
5848 $exprops[] = "\0TStyle\0_customStyle";
5849 if ($this->_displayStyle==='Fixed')
5850 $exprops[] = "\0TStyle\0_displayStyle";
5852 public function __construct($style=null)
5854 parent::__construct();
5856 $this->copyFrom($style);
5858 public function __clone()
5860 if($this->_font!==null)
5861 $this->_font = clone($this->_font);
5863 public function getBackColor()
5865 return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
5867 public function setBackColor($value)
5869 if(trim($value)==='')
5870 unset($this->_fields['background-color']);
5872 $this->_fields['background-color']=$value;
5874 public function getBorderColor()
5876 return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
5878 public function setBorderColor($value)
5880 if(trim($value)==='')
5881 unset($this->_fields['border-color']);
5883 $this->_fields['border-color']=$value;
5885 public function getBorderStyle()
5887 return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
5889 public function setBorderStyle($value)
5891 if(trim($value)==='')
5892 unset($this->_fields['border-style']);
5894 $this->_fields['border-style']=$value;
5896 public function getBorderWidth()
5898 return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
5900 public function setBorderWidth($value)
5902 if(trim($value)==='')
5903 unset($this->_fields['border-width']);
5905 $this->_fields['border-width']=$value;
5907 public function getCssClass()
5909 return $this->_class===null?'':$this->_class;
5911 public function hasCssClass()
5913 return ($this->_class!==null);
5915 public function setCssClass($value)
5917 $this->_class=$value;
5919 public function getFont()
5921 if($this->_font===null)
5922 $this->_font=new TFont;
5923 return $this->_font;
5925 public function hasFont()
5927 return $this->_font !== null;
5929 public function setDisplayStyle($value)
5931 $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
5932 switch($this->_displayStyle)
5934 case TDisplayStyle::None:
5935 $this->_fields['display'] = 'none';
5937 case TDisplayStyle::Dynamic:
5938 $this->_fields['display'] = ''; break;
5939 case TDisplayStyle::Fixed:
5940 $this->_fields['visibility'] = 'visible';
5942 case TDisplayStyle::Hidden:
5943 $this->_fields['visibility'] = 'hidden';
5947 public function getDisplayStyle()
5949 return $this->_displayStyle;
5951 public function getForeColor()
5953 return isset($this->_fields['color'])?$this->_fields['color']:'';
5955 public function setForeColor($value)
5957 if(trim($value)==='')
5958 unset($this->_fields['color']);
5960 $this->_fields['color']=$value;
5962 public function getHeight()
5964 return isset($this->_fields['height'])?$this->_fields['height']:'';
5966 public function setHeight($value)
5968 if(trim($value)==='')
5969 unset($this->_fields['height']);
5971 $this->_fields['height']=$value;
5973 public function getCustomStyle()
5975 return $this->_customStyle===null?'':$this->_customStyle;
5977 public function setCustomStyle($value)
5979 $this->_customStyle=$value;
5981 public function getStyleField($name)
5983 return isset($this->_fields[$name])?$this->_fields[$name]:'';
5985 public function setStyleField($name,$value)
5987 $this->_fields[$name]=$value;
5989 public function clearStyleField($name)
5991 unset($this->_fields[$name]);
5993 public function hasStyleField($name)
5995 return isset($this->_fields[$name]);
5997 public function getWidth()
5999 return isset($this->_fields['width'])?$this->_fields['width']:'';
6001 public function setWidth($value)
6003 $this->_fields['width']=$value;
6005 public function reset()
6007 $this->_fields=array();
6010 $this->_customStyle=null;
6012 public function copyFrom($style)
6014 if($style instanceof TStyle)
6016 $this->_fields=array_merge($this->_fields,$style->_fields);
6017 if($style->_class!==null)
6018 $this->_class=$style->_class;
6019 if($style->_customStyle!==null)
6020 $this->_customStyle=$style->_customStyle;
6021 if($style->_font!==null)
6022 $this->getFont()->copyFrom($style->_font);
6025 public function mergeWith($style)
6027 if($style instanceof TStyle)
6029 $this->_fields=array_merge($style->_fields,$this->_fields);
6030 if($this->_class===null)
6031 $this->_class=$style->_class;
6032 if($this->_customStyle===null)
6033 $this->_customStyle=$style->_customStyle;
6034 if($style->_font!==null)
6035 $this->getFont()->mergeWith($style->_font);
6038 public function addAttributesToRender($writer)
6040 if($this->_customStyle!==null)
6042 foreach(explode(';',$this->_customStyle) as $style)
6044 $arr=explode(':',$style,2);
6045 if(isset($arr[1]) && trim($arr[0])!=='')
6046 $writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
6049 $writer->addStyleAttributes($this->_fields);
6050 if($this->_font!==null)
6051 $this->_font->addAttributesToRender($writer);
6052 if($this->_class!==null)
6053 $writer->addAttribute('class',$this->_class);
6055 public function getStyleFields()
6057 return $this->_fields;
6060 class TDisplayStyle extends TEnumerable
6063 const Dynamic='Dynamic';
6064 const Fixed='Fixed';
6065 const Hidden='Hidden';
6067 class TTableStyle extends TStyle
6069 private $_backImageUrl=null;
6070 private $_horizontalAlign=null;
6071 private $_cellPadding=null;
6072 private $_cellSpacing=null;
6073 private $_gridLines=null;
6074 private $_borderCollapse=null;
6075 protected function _getZappableSleepProps(&$exprops)
6077 parent::_getZappableSleepProps($exprops);
6078 if ($this->_backImageUrl===null)
6079 $exprops[] = "\0TTableStyle\0_backImageUrl";
6080 if ($this->_horizontalAlign===null)
6081 $exprops[] = "\0TTableStyle\0_horizontalAlign";
6082 if ($this->_cellPadding===null)
6083 $exprops[] = "\0TTableStyle\0_cellPadding";
6084 if ($this->_cellSpacing===null)
6085 $exprops[] = "\0TTableStyle\0_cellSpacing";
6086 if ($this->_gridLines===null)
6087 $exprops[] = "\0TTableStyle\0_gridLines";
6088 if ($this->_borderCollapse===null)
6089 $exprops[] = "\0TTableStyle\0_borderCollapse";
6091 public function reset()
6093 $this->_backImageUrl=null;
6094 $this->_horizontalAlign=null;
6095 $this->_cellPadding=null;
6096 $this->_cellSpacing=null;
6097 $this->_gridLines=null;
6098 $this->_borderCollapse=null;
6100 public function copyFrom($style)
6102 parent::copyFrom($style);
6103 if($style instanceof TTableStyle)
6105 if($style->_backImageUrl!==null)
6106 $this->_backImageUrl=$style->_backImageUrl;
6107 if($style->_horizontalAlign!==null)
6108 $this->_horizontalAlign=$style->_horizontalAlign;
6109 if($style->_cellPadding!==null)
6110 $this->_cellPadding=$style->_cellPadding;
6111 if($style->_cellSpacing!==null)
6112 $this->_cellSpacing=$style->_cellSpacing;
6113 if($style->_gridLines!==null)
6114 $this->_gridLines=$style->_gridLines;
6115 if($style->_borderCollapse!==null)
6116 $this->_borderCollapse=$style->_borderCollapse;
6119 public function mergeWith($style)
6121 parent::mergeWith($style);
6122 if($style instanceof TTableStyle)
6124 if($this->_backImageUrl===null && $style->_backImageUrl!==null)
6125 $this->_backImageUrl=$style->_backImageUrl;
6126 if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6127 $this->_horizontalAlign=$style->_horizontalAlign;
6128 if($this->_cellPadding===null && $style->_cellPadding!==null)
6129 $this->_cellPadding=$style->_cellPadding;
6130 if($this->_cellSpacing===null && $style->_cellSpacing!==null)
6131 $this->_cellSpacing=$style->_cellSpacing;
6132 if($this->_gridLines===null && $style->_gridLines!==null)
6133 $this->_gridLines=$style->_gridLines;
6134 if($this->_borderCollapse===null && $style->_borderCollapse!==null)
6135 $this->_borderCollapse=$style->_borderCollapse;
6138 public function addAttributesToRender($writer)
6140 if(($url=trim($this->getBackImageUrl()))!=='')
6141 $writer->addStyleAttribute('background-image','url('.$url.')');
6142 if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6143 $writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
6144 if(($cellPadding=$this->getCellPadding())>=0)
6145 $writer->addAttribute('cellpadding',"$cellPadding");
6146 if(($cellSpacing=$this->getCellSpacing())>=0)
6147 $writer->addAttribute('cellspacing',"$cellSpacing");
6148 if($this->getBorderCollapse())
6149 $writer->addStyleAttribute('border-collapse','collapse');
6150 switch($this->getGridLines())
6152 case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
6153 case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
6154 case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
6156 parent::addAttributesToRender($writer);
6158 public function getBackImageUrl()
6160 return $this->_backImageUrl===null?'':$this->_backImageUrl;
6162 public function setBackImageUrl($value)
6164 $this->_backImageUrl=$value;
6166 public function getHorizontalAlign()
6168 return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6170 public function setHorizontalAlign($value)
6172 $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6174 public function getCellPadding()
6176 return $this->_cellPadding===null?-1:$this->_cellPadding;
6178 public function setCellPadding($value)
6180 if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
6181 throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
6183 public function getCellSpacing()
6185 return $this->_cellSpacing===null?-1:$this->_cellSpacing;
6187 public function setCellSpacing($value)
6189 if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
6190 throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
6192 public function getGridLines()
6194 return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
6196 public function setGridLines($value)
6198 $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
6200 public function getBorderCollapse()
6202 return $this->_borderCollapse===null?false:$this->_borderCollapse;
6204 public function setBorderCollapse($value)
6206 $this->_borderCollapse=TPropertyValue::ensureBoolean($value);
6209 class TTableItemStyle extends TStyle
6211 private $_horizontalAlign=null;
6212 private $_verticalAlign=null;
6213 private $_wrap=null;
6214 protected function _getZappableSleepProps(&$exprops)
6216 parent::_getZappableSleepProps($exprops);
6217 if ($this->_horizontalAlign===null)
6218 $exprops[] = "\0TTableItemStyle\0_horizontalAlign";
6219 if ($this->_verticalAlign===null)
6220 $exprops[] = "\0TTableItemStyle\0_verticalAlign";
6221 if ($this->_wrap===null)
6222 $exprops[] = "\0TTableItemStyle\0_wrap";
6224 public function reset()
6227 $this->_verticalAlign=null;
6228 $this->_horizontalAlign=null;
6231 public function copyFrom($style)
6233 parent::copyFrom($style);
6234 if($style instanceof TTableItemStyle)
6236 if($this->_verticalAlign===null && $style->_verticalAlign!==null)
6237 $this->_verticalAlign=$style->_verticalAlign;
6238 if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6239 $this->_horizontalAlign=$style->_horizontalAlign;
6240 if($this->_wrap===null && $style->_wrap!==null)
6241 $this->_wrap=$style->_wrap;
6244 public function mergeWith($style)
6246 parent::mergeWith($style);
6247 if($style instanceof TTableItemStyle)
6249 if($style->_verticalAlign!==null)
6250 $this->_verticalAlign=$style->_verticalAlign;
6251 if($style->_horizontalAlign!==null)
6252 $this->_horizontalAlign=$style->_horizontalAlign;
6253 if($style->_wrap!==null)
6254 $this->_wrap=$style->_wrap;
6257 public function addAttributesToRender($writer)
6259 if(!$this->getWrap())
6260 $writer->addStyleAttribute('white-space','nowrap');
6261 if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6262 $writer->addAttribute('align',strtolower($horizontalAlign));
6263 if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
6264 $writer->addAttribute('valign',strtolower($verticalAlign));
6265 parent::addAttributesToRender($writer);
6267 public function getHorizontalAlign()
6269 return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6271 public function setHorizontalAlign($value)
6273 $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6275 public function getVerticalAlign()
6277 return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
6279 public function setVerticalAlign($value)
6281 $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
6283 public function getWrap()
6285 return $this->_wrap===null?true:$this->_wrap;
6287 public function setWrap($value)
6289 $this->_wrap=TPropertyValue::ensureBoolean($value);
6292 class THorizontalAlign extends TEnumerable
6294 const NotSet='NotSet';
6296 const Right='Right';
6297 const Center='Center';
6298 const Justify='Justify';
6300 class TVerticalAlign extends TEnumerable
6302 const NotSet='NotSet';
6304 const Bottom='Bottom';
6305 const Middle='Middle';
6307 class TTableGridLines extends TEnumerable
6310 const Horizontal='Horizontal';
6311 const Vertical='Vertical';
6314 class TWebControlAdapter extends TControlAdapter
6316 public function render($writer)
6318 $this->renderBeginTag($writer);
6319 $this->renderContents($writer);
6320 $this->renderEndTag($writer);
6322 public function renderBeginTag($writer)
6324 $this->getControl()->renderBeginTag($writer);
6326 public function renderContents($writer)
6328 $this->getControl()->renderContents($writer);
6330 public function renderEndTag($writer)
6332 $this->getControl()->renderEndTag($writer);
6335 class TWebControlDecorator extends TComponent {
6336 private $_internalonly;
6337 private $_usestate = false;
6339 private $_outercontrol;
6340 private $_addedTemplateDecoration=false;
6341 private $_pretagtext = '';
6342 private $_precontentstext = '';
6343 private $_postcontentstext = '';
6344 private $_posttagtext = '';
6345 private $_pretagtemplate;
6346 private $_precontentstemplate;
6347 private $_postcontentstemplate;
6348 private $_posttagtemplate;
6349 public function __construct($control, $onlyinternal = false) {
6350 $this->_control = $control;
6351 $this->_internalonly = $onlyinternal;
6353 public function getUseState()
6355 return $this->_usestate;
6357 public function setUseState($value)
6359 $this->_usestate = TPropertyValue::ensureBoolean($value);
6361 public function getPreTagText() {
6362 return $this->_pretagtext;
6364 public function setPreTagText($value) {
6365 if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6366 $this->_pretagtext = TPropertyValue::ensureString($value);
6368 public function getPreContentsText() {
6369 return $this->_precontentstext;
6371 public function setPreContentsText($value) {
6372 if(!$this->_control->getIsSkinApplied())
6373 $this->_precontentstext = TPropertyValue::ensureString($value);
6375 public function getPostContentsText() {
6376 return $this->_postcontentstext;
6378 public function setPostContentsText($value) {
6379 if(!$this->_control->getIsSkinApplied())
6380 $this->_postcontentstext = TPropertyValue::ensureString($value);
6382 public function getPostTagText() {
6383 return $this->_posttagtext;
6385 public function setPostTagText($value) {
6386 if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6387 $this->_posttagtext = TPropertyValue::ensureString($value);
6389 public function getPreTagTemplate() {
6390 return $this->_pretagtemplate;
6392 public function setPreTagTemplate($value) {
6393 if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6394 $this->_pretagtemplate = $value;
6396 public function getPreContentsTemplate() {
6397 return $this->_precontentstemplate;
6399 public function setPreContentsTemplate($value) {
6400 if(!$this->_control->getIsSkinApplied())
6401 $this->_precontentstemplate = $value;
6403 public function getPostContentsTemplate() {
6404 return $this->_postcontentstemplate;
6406 public function setPostContentsTemplate($value) {
6407 if(!$this->_control->getIsSkinApplied())
6408 $this->_postcontentstemplate = $value;
6410 public function getPostTagTemplate() {
6411 return $this->_posttagtemplate;
6413 public function setPostTagTemplate($value) {
6414 if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6415 $this->_posttagtemplate = $value;
6417 public function instantiate($outercontrol = null) {
6418 if($this->getPreTagTemplate() || $this->getPreContentsTemplate() ||
6419 $this->getPostContentsTemplate() || $this->getPostTagTemplate()) {
6420 $this->_outercontrol = $outercontrol;
6421 if($this->getUseState())
6422 $this->ensureTemplateDecoration();
6424 $this->_control->getPage()->onSaveStateComplete[] = array($this, 'ensureTemplateDecoration');
6427 public function ensureTemplateDecoration($sender=null, $param=null) {
6428 $control = $this->_control;
6429 $outercontrol = $this->_outercontrol;
6430 if($outercontrol === null)
6431 $outercontrol = $control;
6432 if($this->_addedTemplateDecoration)
6433 return $this->_addedTemplateDecoration;
6434 $this->_addedTemplateDecoration = true;
6435 if($this->getPreContentsTemplate())
6437 $precontents = Prado::createComponent('TCompositeControl');
6438 $this->getPreContentsTemplate()->instantiateIn($precontents);
6439 $control->getControls()->insertAt(0, $precontents);
6441 if($this->getPostContentsTemplate())
6443 $postcontents = Prado::createComponent('TCompositeControl');
6444 $this->getPostContentsTemplate()->instantiateIn($postcontents);
6445 $control->getControls()->add($postcontents);
6447 if(!$outercontrol->getParent())
6448 return $this->_addedTemplateDecoration;
6449 if($this->getPreTagTemplate())
6451 $pretag = Prado::createComponent('TCompositeControl');
6452 $this->getPreTagTemplate()->instantiateIn($pretag);
6453 $outercontrol->getParent()->getControls()->insertBefore($outercontrol, $pretag);
6455 if($this->getPostTagTemplate())
6457 $posttag = Prado::createComponent('TCompositeControl');
6458 $this->getPostTagTemplate()->instantiateIn($posttag);
6459 $outercontrol->getParent()->getControls()->insertAfter($outercontrol, $posttag);
6463 public function renderPreTagText($writer) {
6464 $writer->write($this->getPreTagText());
6466 public function renderPreContentsText($writer) {
6467 $writer->write($this->getPreContentsText());
6469 public function renderPostContentsText($writer) {
6470 $writer->write($this->getPostContentsText());
6472 public function renderPostTagText($writer) {
6473 $writer->write($this->getPostTagText());
6476 class TWebControl extends TControl implements IStyleable
6478 private $_ensureid=false;
6479 protected $_decorator;
6480 public function setEnsureId($value)
6482 $this->_ensureid |= TPropertyValue::ensureBoolean($value);
6484 public function getEnsureId()
6486 return $this->_ensureid;
6488 public function getDecorator($create=true)
6490 if($create && !$this->_decorator)
6491 $this->_decorator = Prado::createComponent('TWebControlDecorator', $this);
6492 return $this->_decorator;
6494 public function copyBaseAttributes(TWebControl $control)
6496 $this->setAccessKey($control->getAccessKey());
6497 $this->setToolTip($control->getToolTip());
6498 $this->setTabIndex($control->getTabIndex());
6499 if(!$control->getEnabled())
6500 $this->setEnabled(false);
6501 if($control->getHasAttributes())
6502 $this->getAttributes()->copyFrom($control->getAttributes());
6504 public function getAccessKey()
6506 return $this->getViewState('AccessKey','');
6508 public function setAccessKey($value)
6510 if(strlen($value)>1)
6511 throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
6512 $this->setViewState('AccessKey',$value,'');
6514 public function getBackColor()
6516 if($style=$this->getViewState('Style',null))
6517 return $style->getBackColor();
6521 public function setBackColor($value)
6523 $this->getStyle()->setBackColor($value);
6525 public function getBorderColor()
6527 if($style=$this->getViewState('Style',null))
6528 return $style->getBorderColor();
6532 public function setBorderColor($value)
6534 $this->getStyle()->setBorderColor($value);
6536 public function getBorderStyle()
6538 if($style=$this->getViewState('Style',null))
6539 return $style->getBorderStyle();
6543 public function setBorderStyle($value)
6545 $this->getStyle()->setBorderStyle($value);
6547 public function getBorderWidth()
6549 if($style=$this->getViewState('Style',null))
6550 return $style->getBorderWidth();
6554 public function setBorderWidth($value)
6556 $this->getStyle()->setBorderWidth($value);
6558 public function getFont()
6560 return $this->getStyle()->getFont();
6562 public function getForeColor()
6564 if($style=$this->getViewState('Style',null))
6565 return $style->getForeColor();
6569 public function setForeColor($value)
6571 $this->getStyle()->setForeColor($value);
6573 public function getHeight()
6575 if($style=$this->getViewState('Style',null))
6576 return $style->getHeight();
6580 public function setDisplay($value)
6582 $this->getStyle()->setDisplayStyle($value);
6584 public function getDisplay()
6586 return $this->getStyle()->getDisplayStyle();
6588 public function setCssClass($value)
6590 $this->getStyle()->setCssClass($value);
6592 public function getCssClass()
6594 if($style=$this->getViewState('Style',null))
6595 return $style->getCssClass();
6599 public function setHeight($value)
6601 $this->getStyle()->setHeight($value);
6603 public function getHasStyle()
6605 return $this->getViewState('Style',null)!==null;
6607 protected function createStyle()
6611 public function getStyle()
6613 if($style=$this->getViewState('Style',null))
6617 $style=$this->createStyle();
6618 $this->setViewState('Style',$style,null);
6622 public function setStyle($value)
6624 if(is_string($value))
6625 $this->getStyle()->setCustomStyle($value);
6627 throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
6629 public function clearStyle()
6631 $this->clearViewState('Style');
6633 public function getTabIndex()
6635 return $this->getViewState('TabIndex',0);
6637 public function setTabIndex($value)
6639 $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
6641 protected function getTagName()
6645 public function getToolTip()
6647 return $this->getViewState('ToolTip','');
6649 public function setToolTip($value)
6651 $this->setViewState('ToolTip',$value,'');
6653 public function getWidth()
6655 if($style=$this->getViewState('Style',null))
6656 return $style->getWidth();
6660 public function setWidth($value)
6662 $this->getStyle()->setWidth($value);
6664 public function onPreRender($param) {
6665 if($decorator = $this->getDecorator(false))
6666 $decorator->instantiate();
6667 parent::onPreRender($param);
6669 protected function addAttributesToRender($writer)
6671 if($this->getID()!=='' || $this->getEnsureId())
6672 $writer->addAttribute('id',$this->getClientID());
6673 if(($accessKey=$this->getAccessKey())!=='')
6674 $writer->addAttribute('accesskey',$accessKey);
6675 if(!$this->getEnabled())
6676 $writer->addAttribute('disabled','disabled');
6677 if(($tabIndex=$this->getTabIndex())>0)
6678 $writer->addAttribute('tabindex',"$tabIndex");
6679 if(($toolTip=$this->getToolTip())!=='')
6680 $writer->addAttribute('title',$toolTip);
6681 if($style=$this->getViewState('Style',null))
6682 $style->addAttributesToRender($writer);
6683 if($this->getHasAttributes())
6685 foreach($this->getAttributes() as $name=>$value)
6686 $writer->addAttribute($name,$value);
6689 public function render($writer)
6691 $this->renderBeginTag($writer);
6692 $this->renderContents($writer);
6693 $this->renderEndTag($writer);
6695 public function renderBeginTag($writer)
6697 if($decorator = $this->getDecorator(false)) {
6698 $decorator->renderPreTagText($writer);
6699 $this->addAttributesToRender($writer);
6700 $writer->renderBeginTag($this->getTagName());
6701 $decorator->renderPreContentsText($writer);
6703 $this->addAttributesToRender($writer);
6704 $writer->renderBeginTag($this->getTagName());
6707 public function renderContents($writer)
6709 parent::renderChildren($writer);
6711 public function renderEndTag($writer)
6713 if($decorator = $this->getDecorator(false)) {
6714 $decorator->renderPostContentsText($writer);
6715 $writer->renderEndTag();
6716 $decorator->renderPostTagText($writer);
6718 $writer->renderEndTag($writer);
6721 class TCompositeControl extends TControl implements INamingContainer
6723 protected function initRecursive($namingContainer=null)
6725 $this->ensureChildControls();
6726 parent::initRecursive($namingContainer);
6729 class TTemplateControl extends TCompositeControl
6731 const EXT_TEMPLATE='.tpl';
6732 private static $_template=array();
6733 private $_localTemplate=null;
6734 private $_master=null;
6735 private $_masterClass='';
6736 private $_contents=array();
6737 private $_placeholders=array();
6738 public function getTemplate()
6740 if($this->_localTemplate===null)
6742 $class=get_class($this);
6743 if(!isset(self::$_template[$class]))
6744 self::$_template[$class]=$this->loadTemplate();
6745 return self::$_template[$class];
6748 return $this->_localTemplate;
6750 public function setTemplate($value)
6752 $this->_localTemplate=$value;
6754 public function getIsSourceTemplateControl()
6756 if(($template=$this->getTemplate())!==null)
6757 return $template->getIsSourceTemplate();
6761 public function getTemplateDirectory()
6763 if(($template=$this->getTemplate())!==null)
6764 return $template->getContextPath();
6768 protected function loadTemplate()
6770 $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
6773 public function createChildControls()
6775 if($tpl=$this->getTemplate())
6777 foreach($tpl->getDirective() as $name=>$value)
6779 if(is_string($value))
6780 $this->setSubProperty($name,$value);
6782 throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
6784 $tpl->instantiateIn($this);
6787 public function registerContent($id,TContent $object)
6789 if(isset($this->_contents[$id]))
6790 throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
6792 $this->_contents[$id]=$object;
6794 public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
6796 if(isset($this->_placeholders[$id]))
6797 throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
6799 $this->_placeholders[$id]=$object;
6801 public function getMasterClass()
6803 return $this->_masterClass;
6805 public function setMasterClass($value)
6807 $this->_masterClass=$value;
6809 public function getMaster()
6811 return $this->_master;
6813 public function injectContent($id,$content)
6815 if(isset($this->_placeholders[$id]))
6817 $placeholder=$this->_placeholders[$id];
6818 $controls=$placeholder->getParent()->getControls();
6819 $loc=$controls->remove($placeholder);
6820 $controls->insertAt($loc,$content);
6823 throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
6825 protected function initRecursive($namingContainer=null)
6827 $this->ensureChildControls();
6828 if($this->_masterClass!=='')
6830 $master=Prado::createComponent($this->_masterClass);
6831 if(!($master instanceof TTemplateControl))
6832 throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
6833 $this->_master=$master;
6834 $this->getControls()->clear();
6835 $this->getControls()->add($master);
6836 $master->ensureChildControls();
6837 foreach($this->_contents as $id=>$content)
6838 $master->injectContent($id,$content);
6840 else if(!empty($this->_contents))
6841 throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
6842 parent::initRecursive($namingContainer);
6844 public function tryToUpdateView($arObj, $throwExceptions = false)
6846 $objAttrs = get_class_vars(get_class($arObj));
6847 foreach (array_keys($objAttrs) as $key)
6851 if ($key != "RELATIONS")
6853 $control = $this->{$key};
6854 if ($control instanceof TTextBox)
6855 $control->Text = $arObj->{$key};
6856 elseif ($control instanceof TCheckBox)
6857 $control->Checked = (boolean) $arObj->{$key};
6858 elseif ($control instanceof TDatePicker)
6859 $control->Date = $arObj->{$key};
6863 foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
6865 $relControl = $this->{$relKey};
6866 switch ($relValues[0])
6868 case TActiveRecord::BELONGS_TO:
6869 case TActiveRecord::HAS_ONE:
6870 $relControl->Text = $arObj->{$relKey};
6872 case TActiveRecord::HAS_MANY:
6873 if ($relControl instanceof TListControl)
6875 $relControl->DataSource = $arObj->{$relKey};
6876 $relControl->dataBind();
6884 catch (Exception $ex)
6886 if ($throwExceptions)
6891 public function tryToUpdateAR($arObj, $throwExceptions = false)
6893 $objAttrs = get_class_vars(get_class($arObj));
6894 foreach (array_keys($objAttrs) as $key)
6898 if ($key == "RELATIONS")
6900 $control = $this->{$key};
6901 if ($control instanceof TTextBox)
6902 $arObj->{$key} = $control->Text;
6903 elseif ($control instanceof TCheckBox)
6904 $arObj->{$key} = $control->Checked;
6905 elseif ($control instanceof TDatePicker)
6906 $arObj->{$key} = $control->Date;
6908 catch (Exception $ex)
6910 if ($throwExceptions)
6916 class TForm extends TControl
6918 public function onInit($param)
6920 parent::onInit($param);
6921 $this->getPage()->setForm($this);
6923 protected function addAttributesToRender($writer)
6925 $writer->addAttribute('id',$this->getClientID());
6926 $writer->addAttribute('method',$this->getMethod());
6927 $uri=$this->getRequest()->getRequestURI();
6928 $writer->addAttribute('action',str_replace('&','&',str_replace('&','&',$uri)));
6929 if(($enctype=$this->getEnctype())!=='')
6930 $writer->addAttribute('enctype',$enctype);
6931 $attributes=$this->getAttributes();
6932 $attributes->remove('action');
6933 $writer->addAttributes($attributes);
6934 if(($butt=$this->getDefaultButton())!=='')
6936 if(($button=$this->findControl($butt))!==null)
6937 $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
6939 throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
6942 public function render($writer)
6944 $page=$this->getPage();
6945 $this->addAttributesToRender($writer);
6946 $writer->renderBeginTag('form');
6947 $cs=$page->getClientScript();
6948 if($page->getClientSupportsJavaScript())
6950 $cs->renderHiddenFieldsBegin($writer);
6951 $cs->renderScriptFilesBegin($writer);
6952 $cs->renderBeginScripts($writer);
6953 $page->beginFormRender($writer);
6954 $this->renderChildren($writer);
6955 $cs->renderHiddenFieldsEnd($writer);
6956 $page->endFormRender($writer);
6957 $cs->renderScriptFilesEnd($writer);
6958 $cs->renderEndScripts($writer);
6962 $cs->renderHiddenFieldsBegin($writer);
6963 $page->beginFormRender($writer);
6964 $this->renderChildren($writer);
6965 $page->endFormRender($writer);
6966 $cs->renderHiddenFieldsEnd($writer);
6968 $writer->renderEndTag();
6970 public function getDefaultButton()
6972 return $this->getViewState('DefaultButton','');
6974 public function setDefaultButton($value)
6976 $this->setViewState('DefaultButton',$value,'');
6978 public function getMethod()
6980 return $this->getViewState('Method','post');
6982 public function setMethod($value)
6984 $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
6986 public function getEnctype()
6988 return $this->getViewState('Enctype','');
6990 public function setEnctype($value)
6992 $this->setViewState('Enctype',$value,'');
6994 public function getName()
6996 return $this->getUniqueID();
6999 class TClientScriptManager extends TApplicationComponent
7001 const SCRIPT_PATH='Web/Javascripts/source';
7002 const PACKAGES_FILE='Web/Javascripts/packages.php';
7003 const CSS_PACKAGES_FILE='Web/Javascripts/css-packages.php';
7005 private $_hiddenFields=array();
7006 private $_beginScripts=array();
7007 private $_endScripts=array();
7008 private $_scriptFiles=array();
7009 private $_headScriptFiles=array();
7010 private $_headScripts=array();
7011 private $_styleSheetFiles=array();
7012 private $_styleSheets=array();
7013 private $_registeredPradoScripts=array();
7014 private static $_pradoScripts;
7015 private static $_pradoPackages;
7016 private $_registeredPradoStyles=array();
7017 private static $_pradoStyles;
7018 private static $_pradoStylePackages;
7019 private $_renderedHiddenFields;
7020 private $_renderedScriptFiles=array();
7021 private $_expandedPradoScripts;
7022 private $_expandedPradoStyles;
7023 public function __construct(TPage $owner)
7025 $this->_page=$owner;
7027 public function getRequiresHead()
7029 return count($this->_styleSheetFiles) || count($this->_styleSheets)
7030 || count($this->_headScriptFiles) || count($this->_headScripts);
7032 public static function getPradoPackages()
7034 return self::$_pradoPackages;
7036 public static function getPradoScripts()
7038 return self::$_pradoScripts;
7040 public function registerPradoScript($name)
7042 $this->registerPradoScriptInternal($name);
7043 $params=func_get_args();
7044 $this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
7046 protected function registerPradoScriptInternal($name)
7048 if(!isset($this->_registeredPradoScripts[$name]))
7050 if(self::$_pradoScripts === null)
7052 $packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::PACKAGES_FILE;
7053 list($packages,$deps)= include($packageFile);
7054 self::$_pradoScripts = $deps;
7055 self::$_pradoPackages = $packages;
7057 if (isset(self::$_pradoScripts[$name]))
7058 $this->_registeredPradoScripts[$name]=true;
7060 throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
7061 if(($packages=array_keys($this->_registeredPradoScripts))!==array())
7063 $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7064 list($path,$baseUrl)=$this->getPackagePathUrl($base);
7065 $packagesUrl=array();
7066 $isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
7067 foreach ($packages as $p)
7069 foreach (self::$_pradoScripts[$p] as $dep)
7071 foreach (self::$_pradoPackages[$dep] as $script)
7072 if (!isset($this->_expandedPradoScripts[$script]))
7074 $this->_expandedPradoScripts[$script] = true;
7077 if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
7078 $packagesUrl[]=$url;
7080 if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))
7082 if(!is_file($filePath=$path.'/min/'.$script))
7084 $dirPath=dirname($filePath);
7085 if(!is_dir($dirPath))
7086 mkdir($dirPath, PRADO_CHMOD, true);
7087 file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script)));
7088 chmod($filePath, PRADO_CHMOD);
7090 $packagesUrl[]=$url;
7096 foreach($packagesUrl as $url)
7097 $this->registerScriptFile($url,$url);
7101 public function getPradoScriptAssetUrl()
7103 $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7104 $assets = Prado::getApplication()->getAssetManager();
7105 return $assets->getPublishedUrl($base);
7107 public function getScriptUrls()
7109 $scripts = array_values($this->_headScriptFiles);
7110 $scripts = array_merge($scripts, array_values($this->_scriptFiles));
7111 $scripts = array_unique($scripts);
7114 protected function getPackagePathUrl($base)
7116 $assets = Prado::getApplication()->getAssetManager();
7117 if(strpos($base, $assets->getBaseUrl())===false)
7119 if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
7122 return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
7126 return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
7129 public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
7131 $options = !is_array($options) ? array() : $options;
7132 $class = new ReflectionClass($callbackHandler);
7133 $clientSide = $callbackHandler->getActiveControl()->getClientSide();
7134 $options = array_merge($options, $clientSide->getOptions()->toArray());
7135 $optionString = TJavaScript::encode($options);
7136 $this->registerPradoScriptInternal('ajax');
7137 $id = $callbackHandler->getUniqueID();
7138 return "new Prado.CallbackRequest('{$id}',{$optionString})";
7140 public function registerCallbackControl($class, $options)
7142 $optionString=TJavaScript::encode($options);
7143 $code="new {$class}({$optionString});";
7144 $this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7145 $this->registerPradoScriptInternal('ajax');
7146 $params=func_get_args();
7147 $this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
7149 public function registerPostBackControl($class,$options)
7151 if($class === null) {
7154 if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
7155 $options['FormID']=$form->getClientID();
7156 $optionString=TJavaScript::encode($options);
7157 $code="new {$class}({$optionString});";
7158 $this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7159 $this->registerPradoScriptInternal('prado');
7160 $params=func_get_args();
7161 $this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
7163 public function registerDefaultButton($panel, $button)
7165 $panelID=is_string($panel)?$panel:$panel->getUniqueID();
7166 if(is_string($button))
7170 $button->setIsDefaultButton(true);
7171 $buttonID=$button->getUniqueID();
7173 $options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
7174 $code = "new Prado.WebUI.DefaultButton($options);";
7175 $this->_endScripts['prado:'.$panelID]=$code;
7176 $this->registerPradoScriptInternal('prado');
7177 $params=array($panelID,$buttonID);
7178 $this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
7180 protected function getDefaultButtonOptions($panelID, $buttonID)
7182 $options['ID'] = TControl::convertUniqueIdToClientId($panelID);
7183 $options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
7184 $options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
7185 $options['EventTarget'] = $buttonID;
7186 $options['Event'] = 'click';
7189 public function registerFocusControl($target)
7191 $this->registerPradoScriptInternal('jquery');
7192 if($target instanceof TControl)
7193 $target=$target->getClientID();
7194 $this->_endScripts['prado:focus'] = 'jQuery(\'#'.$target.'\').focus();';
7195 $params=func_get_args();
7196 $this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
7198 public function registerPradoStyle($name)
7200 $this->registerPradoStyleInternal($name);
7201 $params=func_get_args();
7202 $this->_page->registerCachingAction('Page.ClientScript','registerPradoStyle',$params);
7204 protected function registerPradoStyleInternal($name)
7206 if(!isset($this->_registeredPradoStyles[$name]))
7208 $base = $this->getPradoScriptAssetUrl();
7209 if(self::$_pradoStyles === null)
7211 $packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::CSS_PACKAGES_FILE;
7212 list($packages,$deps)= include($packageFile);
7213 self::$_pradoStyles = $deps;
7214 self::$_pradoStylePackages = $packages;
7216 if (isset(self::$_pradoStyles[$name]))
7217 $this->_registeredPradoStyles[$name]=true;
7219 throw new TInvalidOperationException('csmanager_pradostyle_invalid',$name);
7220 if(($packages=array_keys($this->_registeredPradoStyles))!==array())
7222 $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7223 list($path,$baseUrl)=$this->getPackagePathUrl($base);
7224 $packagesUrl=array();
7225 $isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
7226 foreach ($packages as $p)
7228 foreach (self::$_pradoStyles[$p] as $dep)
7230 foreach (self::$_pradoStylePackages[$dep] as $style)
7231 if (!isset($this->_expandedPradoStyles[$style]))
7233 $this->_expandedPradoStyles[$style] = true;
7234 if (!in_array($url=$baseUrl.'/'.$style,$packagesUrl))
7235 $packagesUrl[]=$url;
7239 foreach($packagesUrl as $url)
7240 $this->registerStyleSheetFile($url,$url);
7244 public function registerStyleSheetFile($key,$url,$media='')
7247 $this->_styleSheetFiles[$key]=$url;
7249 $this->_styleSheetFiles[$key]=array($url,$media);
7250 $params=func_get_args();
7251 $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
7253 public function registerStyleSheet($key,$css,$media='')
7255 $this->_styleSheets[$key]=$css;
7256 $params=func_get_args();
7257 $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
7259 public function getStyleSheetUrls()
7261 $stylesheets = array_values(
7262 array_map(function($e) {
7263 return is_array($e) ? $e[0] : $e;
7264 }, $this->_styleSheetFiles)
7266 foreach(Prado::getApplication()->getAssetManager()->getPublished() as $path=>$url)
7267 if (substr($url,strlen($url)-4)=='.css')
7268 $stylesheets[] = $url;
7269 $stylesheets = array_unique($stylesheets);
7270 return $stylesheets;
7272 public function getStyleSheetCodes()
7274 return array_unique(array_values($this->_styleSheets));
7276 public function registerHeadScriptFile($key,$url)
7278 $this->checkIfNotInRender();
7279 $this->_headScriptFiles[$key]=$url;
7280 $params=func_get_args();
7281 $this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
7283 public function registerHeadScript($key,$script)
7285 $this->checkIfNotInRender();
7286 $this->_headScripts[$key]=$script;
7287 $params=func_get_args();
7288 $this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
7290 public function registerScriptFile($key, $url)
7292 $this->_scriptFiles[$key]=$url;
7293 $params=func_get_args();
7294 $this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
7296 public function registerBeginScript($key,$script)
7298 $this->checkIfNotInRender();
7299 $this->_beginScripts[$key]=$script;
7300 $params=func_get_args();
7301 $this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
7303 public function registerEndScript($key,$script)
7305 $this->_endScripts[$key]=$script;
7306 $params=func_get_args();
7307 $this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
7309 public function registerHiddenField($name,$value)
7311 $this->_hiddenFields[$name]=$value;
7312 $params=func_get_args();
7313 $this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
7315 public function isStyleSheetFileRegistered($key)
7317 return isset($this->_styleSheetFiles[$key]);
7319 public function isStyleSheetRegistered($key)
7321 return isset($this->_styleSheets[$key]);
7323 public function isHeadScriptFileRegistered($key)
7325 return isset($this->_headScriptFiles[$key]);
7327 public function isHeadScriptRegistered($key)
7329 return isset($this->_headScripts[$key]);
7331 public function isScriptFileRegistered($key)
7333 return isset($this->_scriptFiles[$key]);
7335 public function isBeginScriptRegistered($key)
7337 return isset($this->_beginScripts[$key]);
7339 public function isEndScriptRegistered($key)
7341 return isset($this->_endScripts[$key]);
7343 public function hasEndScripts()
7345 return count($this->_endScripts) > 0;
7347 public function hasBeginScripts()
7349 return count($this->_beginScripts) > 0;
7351 public function isHiddenFieldRegistered($key)
7353 return isset($this->_hiddenFields[$key]);
7355 public function renderStyleSheetFiles($writer)
7358 foreach($this->_styleSheetFiles as $url)
7361 $str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
7363 $str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
7365 $writer->write($str);
7367 public function renderStyleSheets($writer)
7369 if(count($this->_styleSheets))
7370 $writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
7372 public function renderHeadScriptFiles($writer)
7374 $this->renderScriptFiles($writer,$this->_headScriptFiles);
7376 public function renderHeadScripts($writer)
7378 $writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
7380 public function renderScriptFilesBegin($writer)
7382 $this->renderAllPendingScriptFiles($writer);
7384 public function renderScriptFilesEnd($writer)
7386 $this->renderAllPendingScriptFiles($writer);
7388 public function markScriptFileAsRendered($url)
7390 $this->_renderedScriptFiles[$url] = $url;
7391 $params=func_get_args();
7392 $this->_page->registerCachingAction('Page.ClientScript','markScriptFileAsRendered',$params);
7394 protected function renderScriptFiles($writer, Array $scripts)
7396 foreach($scripts as $script)
7398 $writer->write(TJavaScript::renderScriptFile($script));
7399 $this->markScriptFileAsRendered($script);
7402 protected function getRenderedScriptFiles()
7404 return $this->_renderedScriptFiles;
7406 public function renderAllPendingScriptFiles($writer)
7408 if(!empty($this->_scriptFiles))
7410 $addedScripts = array_diff($this->_scriptFiles,$this->getRenderedScriptFiles());
7411 $this->renderScriptFiles($writer,$addedScripts);
7414 public function renderBeginScripts($writer)
7416 $writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
7418 public function renderEndScripts($writer)
7420 $writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
7422 public function renderBeginScriptsCallback($writer)
7424 $writer->write(TJavaScript::renderScriptBlocksCallback($this->_beginScripts));
7426 public function renderEndScriptsCallback($writer)
7428 $writer->write(TJavaScript::renderScriptBlocksCallback($this->_endScripts));
7430 public function renderHiddenFieldsBegin($writer)
7432 $this->renderHiddenFieldsInt($writer,true);
7434 public function renderHiddenFieldsEnd($writer)
7436 $this->renderHiddenFieldsInt($writer,false);
7438 public function flushScriptFiles($writer, $control=null)
7440 if(!$this->_page->getIsCallback())
7442 $this->_page->ensureRenderInForm($control);
7443 $this->renderAllPendingScriptFiles($writer);
7446 protected function renderHiddenFieldsInt($writer, $initial)
7448 if ($initial) $this->_renderedHiddenFields = array();
7450 foreach($this->_hiddenFields as $name=>$value)
7452 if (in_array($name,$this->_renderedHiddenFields)) continue;
7453 $id=strtr($name,':','_');
7454 if(is_array($value))
7456 foreach($value as $v)
7457 $str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7461 $str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7463 $this->_renderedHiddenFields[] = $name;
7466 $writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
7468 public function getHiddenFields()
7470 return $this->_hiddenFields;
7472 protected function checkIfNotInRender()
7474 if ($form = $this->_page->InFormRender)
7475 throw new Exception('Operation invalid when page is already rendering');
7478 abstract class TClientSideOptions extends TComponent
7481 protected function setFunction($name, $code)
7483 if(!TJavaScript::isJsLiteral($code))
7484 $code = TJavaScript::quoteJsLiteral($this->ensureFunction($code));
7485 $this->setOption($name, $code);
7487 protected function getOption($name)
7489 if ($this->_options)
7490 return $this->_options->itemAt($name);
7494 protected function setOption($name, $value)
7496 $this->getOptions()->add($name, $value);
7498 public function getOptions()
7500 if (!$this->_options)
7501 $this->_options = Prado::createComponent('System.Collections.TMap');
7502 return $this->_options;
7504 protected function ensureFunction($javascript)
7506 return "function(sender, parameter){ {$javascript} }";
7509 class TPage extends TTemplateControl
7511 const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
7512 const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
7513 const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
7514 const FIELD_PAGESTATE='PRADO_PAGESTATE';
7515 const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
7516 const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
7517 private static $_systemPostFields=array(
7518 'PRADO_POSTBACK_TARGET'=>true,
7519 'PRADO_POSTBACK_PARAMETER'=>true,
7520 'PRADO_LASTFOCUS'=>true,
7521 'PRADO_PAGESTATE'=>true,
7522 'PRADO_CALLBACK_TARGET'=>true,
7523 'PRADO_CALLBACK_PARAMETER'=>true
7527 private $_validators=array();
7528 private $_validated=false;
7531 private $_styleSheet;
7532 private $_clientScript;
7533 protected $_postData;
7534 protected $_restPostData;
7535 protected $_controlsPostDataChanged=array();
7536 protected $_controlsRequiringPostData=array();
7537 protected $_controlsRegisteredForPostData=array();
7538 private $_postBackEventTarget;
7539 private $_postBackEventParameter;
7540 protected $_formRendered=false;
7541 protected $_inFormRender=false;
7543 private $_pagePath='';
7544 private $_enableStateValidation=true;
7545 private $_enableStateEncryption=false;
7546 private $_enableStateCompression=true;
7547 private $_statePersisterClass='System.Web.UI.TPageStatePersister';
7548 private $_statePersister;
7549 private $_cachingStack;
7550 private $_clientState='';
7551 protected $_isLoadingPostData=false;
7552 private $_enableJavaScript=true;
7554 public function __construct()
7556 $this->setPage($this);
7558 public function run($writer)
7560 $this->_writer = $writer;
7561 $this->determinePostBackMode();
7562 if($this->getIsPostBack())
7564 if($this->getIsCallback())
7565 $this->processCallbackRequest($writer);
7567 $this->processPostBackRequest($writer);
7570 $this->processNormalRequest($writer);
7571 $this->_writer = null;
7573 protected function processNormalRequest($writer)
7575 $this->onPreInit(null);
7576 $this->initRecursive();
7577 $this->onInitComplete(null);
7578 $this->onPreLoad(null);
7579 $this->loadRecursive();
7580 $this->onLoadComplete(null);
7581 $this->preRenderRecursive();
7582 $this->onPreRenderComplete(null);
7583 $this->savePageState();
7584 $this->onSaveStateComplete(null);
7585 $this->renderControl($writer);
7586 $this->unloadRecursive();
7588 protected function processPostBackRequest($writer)
7590 $this->onPreInit(null);
7591 $this->initRecursive();
7592 $this->onInitComplete(null);
7593 $this->_restPostData=new TMap;
7594 $this->loadPageState();
7595 $this->processPostData($this->_postData,true);
7596 $this->onPreLoad(null);
7597 $this->loadRecursive();
7598 $this->processPostData($this->_restPostData,false);
7599 $this->raiseChangedEvents();
7600 $this->raisePostBackEvent();
7601 $this->onLoadComplete(null);
7602 $this->preRenderRecursive();
7603 $this->onPreRenderComplete(null);
7604 $this->savePageState();
7605 $this->onSaveStateComplete(null);
7606 $this->renderControl($writer);
7607 $this->unloadRecursive();
7609 protected static function decodeUTF8($data, $enc)
7613 foreach($data as $k=>$v)
7614 $data[$k]=self::decodeUTF8($v, $enc);
7616 } elseif(is_string($data)) {
7617 return iconv('UTF-8',$enc.'//IGNORE',$data);
7622 protected function processCallbackRequest($writer)
7624 Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
7625 Prado::using('System.Web.UI.JuiControls.TJuiControlOptions');
7626 $this->setAdapter(new TActivePageAdapter($this));
7627 $callbackEventParameter = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
7628 if(strlen($callbackEventParameter) > 0)
7629 $this->_postData[TPage::FIELD_CALLBACK_PARAMETER]=TJavaScript::jsonDecode((string)$callbackEventParameter);
7630 if (($g=$this->getApplication()->getGlobalization(false))!==null &&
7631 strtoupper($enc=$g->getCharset())!='UTF-8')
7632 foreach ($this->_postData as $k=>$v)
7633 $this->_postData[$k]=self::decodeUTF8($v, $enc);
7634 $this->onPreInit(null);
7635 $this->initRecursive();
7636 $this->onInitComplete(null);
7637 $this->_restPostData=new TMap;
7638 $this->loadPageState();
7639 $this->processPostData($this->_postData,true);
7640 $this->onPreLoad(null);
7641 $this->loadRecursive();
7642 $this->processPostData($this->_restPostData,false);
7643 $this->raiseChangedEvents();
7644 $this->getAdapter()->processCallbackEvent($writer);
7645 $this->onLoadComplete(null);
7646 $this->preRenderRecursive();
7647 $this->onPreRenderComplete(null);
7648 $this->savePageState();
7649 $this->onSaveStateComplete(null);
7650 $this->getAdapter()->renderCallbackResponse($writer);
7651 $this->unloadRecursive();
7653 public function getCallbackClient()
7655 if($this->getAdapter() !== null)
7656 return $this->getAdapter()->getCallbackClientHandler();
7658 return new TCallbackClientScript();
7660 public function setCallbackClient($client)
7662 $this->getAdapter()->setCallbackClientHandler($client);
7664 public function getCallbackEventTarget()
7666 return $this->getAdapter()->getCallbackEventTarget();
7668 public function setCallbackEventTarget(TControl $control)
7670 $this->getAdapter()->setCallbackEventTarget($control);
7672 public function getCallbackEventParameter()
7674 return $this->getAdapter()->getCallbackEventParameter();
7676 public function setCallbackEventParameter($value)
7678 $this->getAdapter()->setCallbackEventParameter($value);
7680 public function getForm()
7682 return $this->_form;
7684 public function setForm(TForm $form)
7686 if($this->_form===null)
7689 throw new TInvalidOperationException('page_form_duplicated');
7691 public function getValidators($validationGroup=null)
7693 if(!$this->_validators)
7694 $this->_validators=new TList;
7695 if(empty($validationGroup) === true)
7696 return $this->_validators;
7700 foreach($this->_validators as $validator)
7701 if($validator->getValidationGroup()===$validationGroup)
7702 $list->add($validator);
7706 public function validate($validationGroup=null)
7708 $this->_validated=true;
7709 if($this->_validators && $this->_validators->getCount())
7711 if($validationGroup===null)
7713 foreach($this->_validators as $validator)
7714 $validator->validate();
7718 foreach($this->_validators as $validator)
7720 if($validator->getValidationGroup()===$validationGroup)
7721 $validator->validate();
7726 public function getIsValid()
7728 if($this->_validated)
7730 if($this->_validators && $this->_validators->getCount())
7732 foreach($this->_validators as $validator)
7733 if(!$validator->getIsValid())
7739 throw new TInvalidOperationException('page_isvalid_unknown');
7741 public function getTheme()
7743 if(is_string($this->_theme))
7744 $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
7745 return $this->_theme;
7747 public function setTheme($value)
7749 $this->_theme=empty($value)?null:$value;
7751 public function getStyleSheetTheme()
7753 if(is_string($this->_styleSheet))
7754 $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
7755 return $this->_styleSheet;
7757 public function setStyleSheetTheme($value)
7759 $this->_styleSheet=empty($value)?null:$value;
7761 public function applyControlSkin($control)
7763 if(($theme=$this->getTheme())!==null)
7764 $theme->applySkin($control);
7766 public function applyControlStyleSheet($control)
7768 if(($theme=$this->getStyleSheetTheme())!==null)
7769 $theme->applySkin($control);
7771 public function getClientScript()
7773 if(!$this->_clientScript) {
7774 $className = $classPath = $this->getService()->getClientScriptManagerClass();
7775 Prado::using($className);
7776 if(($pos=strrpos($className,'.'))!==false)
7777 $className=substr($className,$pos+1);
7778 if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
7779 throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
7780 $this->_clientScript=new $className($this);
7782 return $this->_clientScript;
7784 public function onPreInit($param)
7786 $this->raiseEvent('OnPreInit',$this,$param);
7788 public function onInitComplete($param)
7790 $this->raiseEvent('OnInitComplete',$this,$param);
7792 public function onPreLoad($param)
7794 $this->raiseEvent('OnPreLoad',$this,$param);
7796 public function onLoadComplete($param)
7798 $this->raiseEvent('OnLoadComplete',$this,$param);
7800 public function onPreRenderComplete($param)
7802 $this->raiseEvent('OnPreRenderComplete',$this,$param);
7803 $cs=$this->getClientScript();
7804 $theme=$this->getTheme();
7805 if($theme instanceof ITheme)
7807 foreach($theme->getStyleSheetFiles() as $url)
7808 $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7809 foreach($theme->getJavaScriptFiles() as $url)
7810 $cs->registerHeadScriptFile($url,$url);
7812 $styleSheet=$this->getStyleSheetTheme();
7813 if($styleSheet instanceof ITheme)
7815 foreach($styleSheet->getStyleSheetFiles() as $url)
7816 $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7817 foreach($styleSheet->getJavaScriptFiles() as $url)
7818 $cs->registerHeadScriptFile($url,$url);
7820 if($cs->getRequiresHead() && $this->getHead()===null)
7821 throw new TConfigurationException('page_head_required');
7823 private function getCssMediaType($url)
7825 $segs=explode('.',basename($url));
7827 return $segs[count($segs)-2];
7831 public function onSaveStateComplete($param)
7833 $this->raiseEvent('OnSaveStateComplete',$this,$param);
7835 private function determinePostBackMode()
7837 $postData=$this->getRequest();
7838 if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
7839 $this->_postData=$postData;
7841 public function getIsPostBack()
7843 return $this->_postData!==null;
7845 public function getIsCallback()
7847 return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
7849 public function saveState()
7851 parent::saveState();
7852 $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
7854 public function loadState()
7856 parent::loadState();
7857 $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
7859 protected function loadPageState()
7861 $state=$this->getStatePersister()->load();
7862 $this->loadStateRecursive($state,$this->getEnableViewState());
7864 protected function savePageState()
7866 $state=&$this->saveStateRecursive($this->getEnableViewState());
7867 $this->getStatePersister()->save($state);
7869 protected function isSystemPostField($field)
7871 return isset(self::$_systemPostFields[$field]);
7873 public function registerRequiresPostData($control)
7875 $id=is_string($control)?$control:$control->getUniqueID();
7876 $this->_controlsRegisteredForPostData[$id]=true;
7877 $params=func_get_args();
7878 foreach($this->getCachingStack() as $item)
7879 $item->registerAction('Page','registerRequiresPostData',array($id));
7881 public function getPostBackEventTarget()
7883 if($this->_postBackEventTarget===null && $this->_postData!==null)
7885 $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
7886 if(!empty($eventTarget))
7887 $this->_postBackEventTarget=$this->findControl($eventTarget);
7889 return $this->_postBackEventTarget;
7891 public function setPostBackEventTarget(TControl $control)
7893 $this->_postBackEventTarget=$control;
7895 public function getPostBackEventParameter()
7897 if($this->_postBackEventParameter===null && $this->_postData!==null)
7899 if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
7900 $this->_postBackEventParameter='';
7902 return $this->_postBackEventParameter;
7904 public function setPostBackEventParameter($value)
7906 $this->_postBackEventParameter=$value;
7908 protected function processPostData($postData,$beforeLoad)
7910 $this->_isLoadingPostData=true;
7912 $this->_restPostData=new TMap;
7913 foreach($postData as $key=>$value)
7915 if($this->isSystemPostField($key))
7917 else if($control=$this->findControl($key))
7919 if($control instanceof IPostBackDataHandler)
7921 if($control->loadPostData($key,$postData))
7922 $this->_controlsPostDataChanged[]=$control;
7924 else if($control instanceof IPostBackEventHandler &&
7925 empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
7927 $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); }
7928 unset($this->_controlsRequiringPostData[$key]);
7930 else if($beforeLoad)
7931 $this->_restPostData->add($key,$value);
7933 foreach($this->_controlsRequiringPostData as $key=>$value)
7935 if($control=$this->findControl($key))
7937 if($control instanceof IPostBackDataHandler)
7939 if($control->loadPostData($key,$this->_postData))
7940 $this->_controlsPostDataChanged[]=$control;
7943 throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
7944 unset($this->_controlsRequiringPostData[$key]);
7947 $this->_isLoadingPostData=false;
7949 public function getIsLoadingPostData()
7951 return $this->_isLoadingPostData;
7953 protected function raiseChangedEvents()
7955 foreach($this->_controlsPostDataChanged as $control)
7956 $control->raisePostDataChangedEvent();
7958 protected function raisePostBackEvent()
7960 if(($postBackHandler=$this->getPostBackEventTarget())===null)
7962 else if($postBackHandler instanceof IPostBackEventHandler)
7963 $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
7965 public function getInFormRender()
7967 return $this->_inFormRender;
7969 public function ensureRenderInForm($control)
7971 if(!$this->getIsCallback() && !$this->_inFormRender)
7972 throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
7974 public function beginFormRender($writer)
7976 if($this->_formRendered)
7977 throw new TConfigurationException('page_form_duplicated');
7978 $this->_formRendered=true;
7979 $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
7980 $this->_inFormRender=true;
7982 public function endFormRender($writer)
7986 if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
7987 $focus=$this->_focus->getClientID();
7989 $focus=$this->_focus;
7990 $this->getClientScript()->registerFocusControl($focus);
7992 else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
7993 $this->getClientScript()->registerFocusControl($lastFocus);
7994 $this->_inFormRender=false;
7996 public function setFocus($value)
7998 $this->_focus=$value;
8000 public function getClientSupportsJavaScript()
8002 return $this->_enableJavaScript;
8004 public function setClientSupportsJavaScript($value)
8006 $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
8008 public function getHead()
8010 return $this->_head;
8012 public function setHead(THead $value)
8015 throw new TInvalidOperationException('page_head_duplicated');
8016 $this->_head=$value;
8017 if($this->_title!==null)
8019 $this->_head->setTitle($this->_title);
8023 public function getTitle()
8026 return $this->_head->getTitle();
8028 return $this->_title===null ? '' : $this->_title;
8030 public function setTitle($value)
8033 $this->_head->setTitle($value);
8035 $this->_title=$value;
8037 public function getClientState()
8039 return $this->_clientState;
8041 public function setClientState($state)
8043 $this->_clientState=$state;
8045 public function getRequestClientState()
8047 return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
8049 public function getStatePersisterClass()
8051 return $this->_statePersisterClass;
8053 public function setStatePersisterClass($value)
8055 $this->_statePersisterClass=$value;
8057 public function getStatePersister()
8059 if($this->_statePersister===null)
8061 $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
8062 if(!($this->_statePersister instanceof IPageStatePersister))
8063 throw new TInvalidDataTypeException('page_statepersister_invalid');
8064 $this->_statePersister->setPage($this);
8066 return $this->_statePersister;
8068 public function getEnableStateValidation()
8070 return $this->_enableStateValidation;
8072 public function setEnableStateValidation($value)
8074 $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
8076 public function getEnableStateEncryption()
8078 return $this->_enableStateEncryption;
8080 public function setEnableStateEncryption($value)
8082 $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
8084 public function getEnableStateCompression()
8086 return $this->_enableStateCompression;
8088 public function setEnableStateCompression($value)
8090 $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
8092 public function getPagePath()
8094 return $this->_pagePath;
8096 public function setPagePath($value)
8098 $this->_pagePath=$value;
8100 public function registerCachingAction($context,$funcName,$funcParams)
8102 if($this->_cachingStack)
8104 foreach($this->_cachingStack as $cache)
8105 $cache->registerAction($context,$funcName,$funcParams);
8108 public function getCachingStack()
8110 if(!$this->_cachingStack)
8111 $this->_cachingStack=new TStack;
8112 return $this->_cachingStack;
8114 public function flushWriter()
8117 $this->Response->write($this->_writer->flush());
8120 interface IPageStatePersister
8122 public function getPage();
8123 public function setPage(TPage $page);
8124 public function save($state);
8125 public function load();
8127 class TPageStateFormatter
8129 public static function serialize($page,$data)
8131 $sm=$page->getApplication()->getSecurityManager();
8132 if($page->getEnableStateValidation())
8133 $str=$sm->hashData(serialize($data));
8135 $str=serialize($data);
8136 if($page->getEnableStateCompression() && extension_loaded('zlib'))
8137 $str=gzcompress($str);
8138 if($page->getEnableStateEncryption())
8139 $str=$sm->encrypt($str);
8140 return base64_encode($str);
8142 public static function unserialize($page,$data)
8144 $str=base64_decode($data);
8149 $sm=$page->getApplication()->getSecurityManager();
8150 if($page->getEnableStateEncryption())
8151 $str=$sm->decrypt($str);
8152 if($page->getEnableStateCompression() && extension_loaded('zlib'))
8153 $str=@gzuncompress($str);
8154 if($page->getEnableStateValidation())
8156 if(($str=$sm->validateData($str))!==false)
8157 return unserialize($str);
8160 return unserialize($str);
8165 class TOutputCache extends TControl implements INamingContainer
8167 const CACHE_ID_PREFIX='prado:outputcache';
8168 private $_cacheModuleID='';
8169 private $_dataCached=false;
8170 private $_cacheAvailable=false;
8171 private $_cacheChecked=false;
8172 private $_cacheKey=null;
8173 private $_duration=60;
8174 private $_cache=null;
8177 private $_actions=array();
8178 private $_varyByParam='';
8179 private $_keyPrefix='';
8180 private $_varyBySession=false;
8181 private $_cachePostBack=false;
8182 private $_cacheTime=0;
8183 public function getAllowChildControls()
8185 $this->determineCacheability();
8186 return !$this->_dataCached;
8188 private function determineCacheability()
8190 if(!$this->_cacheChecked)
8192 $this->_cacheChecked=true;
8193 if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
8195 if($this->_cacheModuleID!=='')
8197 $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
8198 if(!($this->_cache instanceof ICache))
8199 throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
8202 $this->_cache=$this->getApplication()->getCache();
8203 if($this->_cache!==null)
8205 $this->_cacheAvailable=true;
8206 $data=$this->_cache->get($this->getCacheKey());
8209 $param=new TOutputCacheCheckDependencyEventParameter;
8210 $param->setCacheTime(isset($data[3])?$data[3]:0);
8211 $this->onCheckDependency($param);
8212 $this->_dataCached=$param->getIsValid();
8215 $this->_dataCached=false;
8216 if($this->_dataCached)
8217 list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
8222 protected function initRecursive($namingContainer=null)
8224 if($this->_cacheAvailable && !$this->_dataCached)
8226 $stack=$this->getPage()->getCachingStack();
8227 $stack->push($this);
8228 parent::initRecursive($namingContainer);
8232 parent::initRecursive($namingContainer);
8234 protected function loadRecursive()
8236 if($this->_cacheAvailable && !$this->_dataCached)
8238 $stack=$this->getPage()->getCachingStack();
8239 $stack->push($this);
8240 parent::loadRecursive();
8245 if($this->_dataCached)
8246 $this->performActions();
8247 parent::loadRecursive();
8250 private function performActions()
8252 $page=$this->getPage();
8253 $cs=$page->getClientScript();
8254 foreach($this->_actions as $action)
8256 if($action[0]==='Page.ClientScript')
8257 call_user_func_array(array($cs,$action[1]),$action[2]);
8258 else if($action[0]==='Page')
8259 call_user_func_array(array($page,$action[1]),$action[2]);
8261 call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
8264 protected function preRenderRecursive()
8266 if($this->_cacheAvailable && !$this->_dataCached)
8268 $stack=$this->getPage()->getCachingStack();
8269 $stack->push($this);
8270 parent::preRenderRecursive();
8274 parent::preRenderRecursive();
8276 protected function loadStateRecursive(&$state,$needViewState=true)
8278 $st=unserialize($state);
8279 parent::loadStateRecursive($st,$needViewState);
8281 protected function &saveStateRecursive($needViewState=true)
8283 if($this->_dataCached)
8284 return $this->_state;
8287 $st=parent::saveStateRecursive($needViewState);
8288 $this->_state=serialize($st);
8289 return $this->_state;
8292 public function registerAction($context,$funcName,$funcParams)
8294 $this->_actions[]=array($context,$funcName,$funcParams);
8296 public function getCacheKey()
8298 if($this->_cacheKey===null)
8299 $this->_cacheKey=$this->calculateCacheKey();
8300 return $this->_cacheKey;
8302 protected function calculateCacheKey()
8304 $key=$this->getBaseCacheKey();
8305 if($this->_varyBySession)
8306 $key.=$this->getSession()->getSessionID();
8307 if($this->_varyByParam!=='')
8310 $request=$this->getRequest();
8311 foreach(explode(',',$this->_varyByParam) as $name)
8314 $params[$name]=$request->itemAt($name);
8316 $key.=serialize($params);
8318 $param=new TOutputCacheCalculateKeyEventParameter;
8319 $this->onCalculateKey($param);
8320 $key.=$param->getCacheKey();
8323 protected function getBaseCacheKey()
8325 return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
8327 public function getCacheModuleID()
8329 return $this->_cacheModuleID;
8331 public function setCacheModuleID($value)
8333 $this->_cacheModuleID=$value;
8335 public function setCacheKeyPrefix($value)
8337 $this->_keyPrefix=$value;
8339 public function getCacheTime()
8341 return $this->_cacheTime;
8343 protected function getCacheDependency()
8347 public function getContentCached()
8349 return $this->_dataCached;
8351 public function getDuration()
8353 return $this->_duration;
8355 public function setDuration($value)
8357 if(($value=TPropertyValue::ensureInteger($value))<0)
8358 throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
8359 $this->_duration=$value;
8361 public function getVaryByParam()
8363 return $this->_varyByParam;
8365 public function setVaryByParam($value)
8367 $this->_varyByParam=trim($value);
8369 public function getVaryBySession()
8371 return $this->_varyBySession;
8373 public function setVaryBySession($value)
8375 $this->_varyBySession=TPropertyValue::ensureBoolean($value);
8377 public function getCachingPostBack()
8379 return $this->_cachePostBack;
8381 public function setCachingPostBack($value)
8383 $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
8385 public function onCheckDependency($param)
8387 $this->raiseEvent('OnCheckDependency',$this,$param);
8389 public function onCalculateKey($param)
8391 $this->raiseEvent('OnCalculateKey',$this,$param);
8393 public function render($writer)
8395 if($this->_dataCached)
8396 $writer->write($this->_contents);
8397 else if($this->_cacheAvailable)
8399 $textwriter = new TTextWriter();
8400 $multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
8401 $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
8402 $stack=$this->getPage()->getCachingStack();
8403 $stack->push($this);
8404 parent::render($htmlWriter);
8406 $content=$textwriter->flush();
8407 $data=array($content,$this->_state,$this->_actions,time());
8408 $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
8411 parent::render($writer);
8414 class TOutputCacheCheckDependencyEventParameter extends TEventParameter
8416 private $_isValid=true;
8417 private $_cacheTime=0;
8418 public function getIsValid()
8420 return $this->_isValid;
8422 public function setIsValid($value)
8424 $this->_isValid=TPropertyValue::ensureBoolean($value);
8426 public function getCacheTime()
8428 return $this->_cacheTime;
8430 public function setCacheTime($value)
8432 $this->_cacheTime=TPropertyValue::ensureInteger($value);
8435 class TOutputCacheCalculateKeyEventParameter extends TEventParameter
8437 private $_cacheKey='';
8438 public function getCacheKey()
8440 return $this->_cacheKey;
8442 public function setCacheKey($value)
8444 $this->_cacheKey=TPropertyValue::ensureString($value);
8447 class TOutputCacheTextWriterMulti extends TTextWriter
8449 protected $_writers;
8450 public function __construct(Array $writers)
8452 $this->_writers = $writers;
8454 public function write($s)
8456 foreach($this->_writers as $writer)
8459 public function flush()
8461 foreach($this->_writers as $writer)
8462 $s = $writer->flush();
8466 class TTemplateManager extends TModule
8468 const TEMPLATE_FILE_EXT='.tpl';
8469 const TEMPLATE_CACHE_PREFIX='prado:template:';
8470 public function init($config)
8472 $this->getService()->setTemplateManager($this);
8474 public function getTemplateByClassName($className)
8476 $class=new ReflectionClass($className);
8477 $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
8478 return $this->getTemplateByFileName($tplFile);
8480 public function getTemplateByFileName($fileName)
8482 if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
8484 if(($cache=$this->getApplication()->getCache())===null)
8485 return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8488 $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
8489 if(is_array($array))
8491 list($template,$timestamps)=$array;
8492 if($this->getApplication()->getMode()===TApplicationMode::Performance)
8495 foreach($timestamps as $tplFile=>$timestamp)
8497 if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
8506 $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8507 $includedFiles=$template->getIncludedFiles();
8508 $timestamps=array();
8509 $timestamps[$fileName]=filemtime($fileName);
8510 foreach($includedFiles as $includedFile)
8511 $timestamps[$includedFile]=filemtime($includedFile);
8512 $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
8519 protected function getLocalizedTemplate($filename)
8521 if(($app=$this->getApplication()->getGlobalization(false))===null)
8522 return is_file($filename)?$filename:null;
8523 foreach($app->getLocalizedResource($filename) as $file)
8525 if(($file=realpath($file))!==false && is_file($file))
8531 class TTemplate extends TApplicationComponent implements ITemplate
8533 const REGEX_RULES='/<!--.*?--!>|<!---.*?--->|<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.\-]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|<prop:([\w\.\-]+)((?:\s*[\w\.\-]+\s*=\s*\'.*?\'|\s*[\w\.\-]+\s*=\s*".*?"|\s*[\w\.\-]+\s*=\s*<%.*?%>)*)\s*\/>/msS';
8534 const CONFIG_DATABIND=0;
8535 const CONFIG_EXPRESSION=1;
8536 const CONFIG_ASSET=2;
8537 const CONFIG_PARAMETER=3;
8538 const CONFIG_LOCALIZATION=4;
8539 const CONFIG_TEMPLATE=5;
8540 private $_tpl=array();
8541 private $_directive=array();
8542 private $_contextPath;
8543 private $_tplFile=null;
8544 private $_startingLine=0;
8546 private $_sourceTemplate=true;
8547 private $_hashCode='';
8548 private $_tplControl=null;
8549 private $_includedFiles=array();
8550 private $_includeAtLine=array();
8551 private $_includeLines=array();
8552 public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
8554 $this->_sourceTemplate=$sourceTemplate;
8555 $this->_contextPath=$contextPath;
8556 $this->_tplFile=$tplFile;
8557 $this->_startingLine=$startingLine;
8558 $this->_content=$template;
8559 $this->_hashCode=md5($template);
8560 $this->parse($template);
8561 $this->_content=null; }
8562 public function getTemplateFile()
8564 return $this->_tplFile;
8566 public function getIsSourceTemplate()
8568 return $this->_sourceTemplate;
8570 public function getContextPath()
8572 return $this->_contextPath;
8574 public function getDirective()
8576 return $this->_directive;
8578 public function getHashCode()
8580 return $this->_hashCode;
8582 public function &getItems()
8586 public function instantiateIn($tplControl,$parentControl=null)
8588 $this->_tplControl=$tplControl;
8589 if($parentControl===null)
8590 $parentControl=$tplControl;
8591 if(($page=$tplControl->getPage())===null)
8592 $page=$this->getService()->getRequestedPage();
8594 $directChildren=array();
8595 foreach($this->_tpl as $key=>$object)
8598 $parent=$parentControl;
8599 else if(isset($controls[$object[0]]))
8600 $parent=$controls[$object[0]];
8603 if(isset($object[2])) {
8604 $component=Prado::createComponent($object[1]);
8605 $properties=&$object[2];
8606 if($component instanceof TControl)
8608 if($component instanceof TOutputCache)
8609 $component->setCacheKeyPrefix($this->_hashCode.$key);
8610 $component->setTemplateControl($tplControl);
8611 if(isset($properties['id']))
8613 if(is_array($properties['id']))
8614 $properties['id']=$component->evaluateExpression($properties['id'][1]);
8615 $tplControl->registerObject($properties['id'],$component);
8617 if(isset($properties['skinid']))
8619 if(is_array($properties['skinid']))
8620 $component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
8622 $component->setSkinID($properties['skinid']);
8623 unset($properties['skinid']);
8625 $component->trackViewState(false);
8626 $component->applyStyleSheetSkin($page);
8627 foreach($properties as $name=>$value)
8628 $this->configureControl($component,$name,$value);
8629 $component->trackViewState(true);
8630 if($parent===$parentControl)
8631 $directChildren[]=$component;
8633 $component->createdOnTemplate($parent);
8634 if($component->getAllowChildControls())
8635 $controls[$key]=$component;
8637 else if($component instanceof TComponent)
8639 $controls[$key]=$component;
8640 if(isset($properties['id']))
8642 if(is_array($properties['id']))
8643 $properties['id']=$component->evaluateExpression($properties['id'][1]);
8644 $tplControl->registerObject($properties['id'],$component);
8645 if(!$component->hasProperty('id'))
8646 unset($properties['id']);
8648 foreach($properties as $name=>$value)
8649 $this->configureComponent($component,$name,$value);
8650 if($parent===$parentControl)
8651 $directChildren[]=$component;
8653 $component->createdOnTemplate($parent);
8658 if($object[1] instanceof TCompositeLiteral)
8660 $o=clone $object[1];
8661 $o->setContainer($tplControl);
8662 if($parent===$parentControl)
8663 $directChildren[]=$o;
8665 $parent->addParsedObject($o);
8669 if($parent===$parentControl)
8670 $directChildren[]=$object[1];
8672 $parent->addParsedObject($object[1]);
8676 foreach($directChildren as $control)
8678 if($control instanceof TComponent)
8679 $control->createdOnTemplate($parentControl);
8681 $parentControl->addParsedObject($control);
8684 protected function configureControl($control,$name,$value)
8686 if(strncasecmp($name,'on',2)===0) $this->configureEvent($control,$name,$value,$control);
8687 else if(($pos=strrpos($name,'.'))===false) $this->configureProperty($control,$name,$value);
8688 else $this->configureSubProperty($control,$name,$value);
8690 protected function configureComponent($component,$name,$value)
8692 if(strpos($name,'.')===false) $this->configureProperty($component,$name,$value);
8693 else $this->configureSubProperty($component,$name,$value);
8695 protected function configureEvent($control,$name,$value,$contextControl)
8697 if(strpos($value,'.')===false)
8698 $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
8700 $control->attachEventHandler($name,array($contextControl,$value));
8702 protected function configureProperty($component,$name,$value)
8704 if(is_array($value))
8708 case self::CONFIG_DATABIND:
8709 $component->bindProperty($name,$value[1]);
8711 case self::CONFIG_EXPRESSION:
8712 if($component instanceof TControl)
8713 $component->autoBindProperty($name,$value[1]);
8716 $setter='set'.$name;
8717 $component->$setter($this->_tplControl->evaluateExpression($value[1]));
8720 case self::CONFIG_TEMPLATE:
8721 $setter='set'.$name;
8722 $component->$setter($value[1]);
8724 case self::CONFIG_ASSET: $setter='set'.$name;
8725 $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
8726 $component->$setter($url);
8728 case self::CONFIG_PARAMETER: $setter='set'.$name;
8729 $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
8731 case self::CONFIG_LOCALIZATION:
8732 $setter='set'.$name;
8733 $component->$setter(Prado::localize($value[1]));
8735 default: throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
8741 if (substr($name,0,2)=='js')
8742 if ($value and !($value instanceof TJavaScriptLiteral))
8743 $value = new TJavaScriptLiteral($value);
8744 $setter='set'.$name;
8745 $component->$setter($value);
8748 protected function configureSubProperty($component,$name,$value)
8750 if(is_array($value))
8754 case self::CONFIG_DATABIND: $component->bindProperty($name,$value[1]);
8756 case self::CONFIG_EXPRESSION: if($component instanceof TControl)
8757 $component->autoBindProperty($name,$value[1]);
8759 $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
8761 case self::CONFIG_TEMPLATE:
8762 $component->setSubProperty($name,$value[1]);
8764 case self::CONFIG_ASSET: $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
8765 $component->setSubProperty($name,$url);
8767 case self::CONFIG_PARAMETER: $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
8769 case self::CONFIG_LOCALIZATION:
8770 $component->setSubProperty($name,Prado::localize($value[1]));
8772 default: throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
8777 $component->setSubProperty($name,$value);
8779 protected function parse($input)
8781 $input=$this->preprocess($input);
8783 $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
8784 $expectPropEnd=false;
8790 $this->_directive=null;
8793 for($i=0;$i<$n;++$i)
8795 $match=&$matches[$i];
8797 $matchStart=$match[0][1];
8798 $matchEnd=$matchStart+strlen($str)-1;
8799 if(strpos($str,'<com:')===0) {
8802 if($matchStart>$textStart)
8803 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8804 $textStart=$matchEnd+1;
8806 $attributes=$this->parseAttributes($match[2][0],$match[2][1]);
8807 $this->validateAttributes($type,$attributes);
8808 $tpl[$c++]=array($container,$type,$attributes);
8809 if($str[strlen($str)-2]!=='/') {
8814 else if(strpos($str,'</com:')===0) {
8817 if($matchStart>$textStart)
8818 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8819 $textStart=$matchEnd+1;
8822 throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
8823 $name=array_pop($stack);
8826 $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8827 throw new TConfigurationException('template_closingtag_expected',$tag);
8829 $container=$tpl[$container][0];
8831 else if(strpos($str,'<%@')===0) {
8834 if($matchStart>$textStart)
8835 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8836 $textStart=$matchEnd+1;
8837 if(isset($tpl[0]) || $this->_directive!==null)
8838 throw new TConfigurationException('template_directive_nonunique');
8839 $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
8841 else if(strpos($str,'<%')===0) {
8844 if($matchStart>$textStart)
8845 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8846 $textStart=$matchEnd+1;
8847 $literal=trim($match[5][0]);
8848 if($str[2]==='=') $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
8849 else if($str[2]==='%') $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
8850 else if($str[2]==='#')
8851 $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
8852 else if($str[2]==='$')
8853 $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
8854 else if($str[2]==='~')
8855 $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
8856 else if($str[2]==='/')
8857 $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'"));
8858 else if($str[2]==='[')
8860 $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
8861 $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
8864 else if(strpos($str,'<prop:')===0) {
8865 if(strrpos($str,'/>')===strlen($str)-2) {
8868 if($matchStart>$textStart)
8869 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8870 $textStart=$matchEnd+1;
8871 $prop=strtolower($match[6][0]);
8872 $attrs=$this->parseAttributes($match[7][0],$match[7][1]);
8873 $attributes=array();
8874 foreach($attrs as $name=>$value)
8875 $attributes[$prop.'.'.$name]=$value;
8876 $type=$tpl[$container][1];
8877 $this->validateAttributes($type,$attributes);
8878 foreach($attributes as $name=>$value)
8880 if(isset($tpl[$container][2][$name]))
8881 throw new TConfigurationException('template_property_duplicated',$name);
8882 $tpl[$container][2][$name]=$value;
8886 $prop=strtolower($match[3][0]);
8887 $stack[] = '@'.$prop;
8890 if($matchStart>$textStart)
8891 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8892 $textStart=$matchEnd+1;
8893 $expectPropEnd=true;
8897 else if(strpos($str,'</prop:')===0) {
8898 $prop=strtolower($match[3][0]);
8900 throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
8901 $name=array_pop($stack);
8902 if($name!=='@'.$prop)
8904 $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8905 throw new TConfigurationException('template_closingtag_expected',$tag);
8907 if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
8909 if($matchStart>$textStart)
8911 $value=substr($input,$textStart,$matchStart-$textStart);
8912 if(substr($prop,-8,8)==='template')
8913 $value=$this->parseTemplateProperty($value,$textStart);
8915 $value=$this->parseAttribute($value);
8918 $type=$tpl[$container][1];
8919 $this->validateAttributes($type,array($prop=>$value));
8920 if(isset($tpl[$container][2][$prop]))
8921 throw new TConfigurationException('template_property_duplicated',$prop);
8922 $tpl[$container][2][$prop]=$value;
8924 else $this->_directive[$prop]=$value;
8925 $textStart=$matchEnd+1;
8927 $expectPropEnd=false;
8930 else if(strpos($str,'<!--')===0) {
8932 throw new TConfigurationException('template_comments_forbidden');
8933 if($matchStart>$textStart)
8934 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8935 $textStart=$matchEnd+1;
8938 throw new TConfigurationException('template_matching_unexpected',$match);
8942 $name=array_pop($stack);
8943 $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8944 throw new TConfigurationException('template_closingtag_expected',$tag);
8946 if($textStart<strlen($input))
8947 $tpl[$c++]=array($container,substr($input,$textStart));
8951 if(($e instanceof TException) && ($e instanceof TTemplateException))
8954 $line=$this->_startingLine+1;
8956 $line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
8957 $this->handleException($e,$line,$input);
8959 if($this->_directive===null)
8960 $this->_directive=array();
8964 foreach($tpl as $id=>$object)
8966 if(isset($object[2]) || $object[0]!==$parent)
8970 if(count($merged[1])===1 && is_string($merged[1][0]))
8971 $objects[$id-1]=array($merged[0],$merged[1][0]);
8973 $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
8975 if(isset($object[2]))
8978 $objects[$id]=$object;
8983 $merged=array($parent,array($object[1]));
8987 $merged[1][]=$object[1];
8991 if(count($merged[1])===1 && is_string($merged[1][0]))
8992 $objects[$id]=array($merged[0],$merged[1][0]);
8994 $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
8999 protected function parseAttributes($str,$offset)
9003 $pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
9004 $attributes=array();
9005 $n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
9006 for($i=0;$i<$n;++$i)
9008 $match=&$matches[$i];
9009 $name=strtolower($match[1][0]);
9010 if(isset($attributes[$name]))
9011 throw new TConfigurationException('template_property_duplicated',$name);
9012 $value=$match[2][0];
9013 if(substr($name,-8,8)==='template')
9015 if($value[0]==='\'' || $value[0]==='"')
9016 $attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
9018 $attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
9022 if($value[0]==='\'' || $value[0]==='"')
9023 $attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
9025 $attributes[$name]=$this->parseAttribute($value);
9030 protected function parseTemplateProperty($content,$offset)
9032 $line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
9033 return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
9035 protected function parseAttribute($value)
9037 if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
9042 for($i=0;$i<$n;++$i)
9044 $match=$matches[0][$i];
9047 $length=strlen($token);
9050 if($offset>$textStart)
9051 $expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
9052 $expr.='.('.substr($token,3,$length-5).')';
9053 $textStart=$offset+$length;
9055 $length=strlen($value);
9056 if($length>$textStart)
9057 $expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
9059 return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
9061 return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
9063 else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
9067 return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
9068 elseif($value[2]==='[')
9069 return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
9070 elseif($value[2]==='$')
9071 return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
9072 elseif($value[2]==='/') {
9073 $literal = trim(substr($value,3,strlen($value)-5));
9074 return array(self::CONFIG_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'");
9080 protected function validateAttributes($type,$attributes)
9082 Prado::using($type);
9083 if(($pos=strrpos($type,'.'))!==false)
9084 $className=substr($type,$pos+1);
9087 $class=new ReflectionClass($className);
9088 if(is_subclass_of($className,'TControl') || $className==='TControl')
9090 foreach($attributes as $name=>$att)
9092 if(($pos=strpos($name,'.'))!==false)
9094 $subname=substr($name,0,$pos);
9095 if(!$class->hasMethod('get'.$subname))
9096 throw new TConfigurationException('template_property_unknown',$type,$subname);
9098 else if(strncasecmp($name,'on',2)===0)
9100 if(!$class->hasMethod($name))
9101 throw new TConfigurationException('template_event_unknown',$type,$name);
9102 else if(!is_string($att))
9103 throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
9107 if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)) )
9109 if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
9110 throw new TConfigurationException('template_property_readonly',$type,$name);
9112 throw new TConfigurationException('template_property_unknown',$type,$name);
9114 else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
9116 if(strcasecmp($name,'id')===0)
9117 throw new TConfigurationException('template_controlid_invalid',$type);
9118 else if(strcasecmp($name,'skinid')===0)
9119 throw new TConfigurationException('template_controlskinid_invalid',$type);
9124 else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
9126 foreach($attributes as $name=>$att)
9128 if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
9129 throw new TConfigurationException('template_databind_forbidden',$type,$name);
9130 if(($pos=strpos($name,'.'))!==false)
9132 $subname=substr($name,0,$pos);
9133 if(!$class->hasMethod('get'.$subname))
9134 throw new TConfigurationException('template_property_unknown',$type,$subname);
9136 else if(strncasecmp($name,'on',2)===0)
9137 throw new TConfigurationException('template_event_forbidden',$type,$name);
9140 if(strcasecmp($name,'id')!==0 && !($class->hasMethod('set'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)))
9142 if($class->hasMethod('get'.$name))
9143 throw new TConfigurationException('template_property_readonly',$type,$name);
9145 throw new TConfigurationException('template_property_unknown',$type,$name);
9151 throw new TConfigurationException('template_component_required',$type);
9153 public function getIncludedFiles()
9155 return $this->_includedFiles;
9157 protected function handleException($e,$line,$input=null)
9159 $srcFile=$this->_tplFile;
9160 if(($n=count($this->_includedFiles))>0) {
9161 for($i=$n-1;$i>=0;--$i)
9163 if($this->_includeAtLine[$i]<=$line)
9165 if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
9167 $line=$line-$this->_includeAtLine[$i]+1;
9168 $srcFile=$this->_includedFiles[$i];
9172 $line=$line-$this->_includeLines[$i]+1;
9176 $exception=new TTemplateException('template_format_invalid',$e->getMessage());
9177 $exception->setLineNumber($line);
9178 if(!empty($srcFile))
9179 $exception->setTemplateFile($srcFile);
9181 $exception->setTemplateSource($input);
9184 protected function preprocess($input)
9186 if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
9188 for($i=0;$i<$n;++$i)
9190 $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
9191 if($filePath!==null && is_file($filePath))
9192 $this->_includedFiles[]=$filePath;
9195 $errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
9196 $this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
9200 for($i=0;$i<$n;++$i)
9202 $ext=file_get_contents($this->_includedFiles[$i]);
9203 $length=strlen($matches[$i][0][0]);
9204 $offset=$base+$matches[$i][0][1];
9205 $this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
9206 $this->_includeLines[$i]=count(explode("\n",$ext));
9207 $input=substr_replace($input,$ext,$offset,$length);
9208 $base+=strlen($ext)-$length;
9213 protected function isClassBehaviorMethod(ReflectionClass $class,$method)
9215 $component=new ReflectionClass('TComponent');
9216 $behaviors=$component->getStaticProperties();
9217 if(!isset($behaviors['_um']))
9219 foreach($behaviors['_um'] as $name=>$list)
9221 if(strtolower($class->getShortName())!==$name && !$class->isSubclassOf($name)) continue;
9222 foreach($list as $param)
9224 if(method_exists($param->getBehavior(),$method))
9231 class TThemeManager extends TModule
9233 const DEFAULT_BASEPATH='themes';
9234 const DEFAULT_THEMECLASS = 'TTheme';
9235 private $_themeClass=self::DEFAULT_THEMECLASS;
9236 private $_initialized=false;
9237 private $_basePath=null;
9238 private $_baseUrl=null;
9239 public function init($config)
9241 $this->_initialized=true;
9242 $service=$this->getService();
9243 if($service instanceof TPageService)
9244 $service->setThemeManager($this);
9246 throw new TConfigurationException('thememanager_service_unavailable');
9248 public function getTheme($name)
9250 $themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
9251 $themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
9252 return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
9254 public function setThemeClass($class) {
9255 $this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
9257 public function getThemeClass() {
9258 return $this->_themeClass;
9260 public function getAvailableThemes()
9263 $basePath=$this->getBasePath();
9264 $folder=@opendir($basePath);
9265 while($file=@readdir($folder))
9267 if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
9273 public function getBasePath()
9275 if($this->_basePath===null)
9277 $this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9278 if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
9279 throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
9280 $this->_basePath=$basePath;
9282 return $this->_basePath;
9284 public function setBasePath($value)
9286 if($this->_initialized)
9287 throw new TInvalidOperationException('thememanager_basepath_unchangeable');
9290 $this->_basePath=Prado::getPathOfNamespace($value);
9291 if($this->_basePath===null || !is_dir($this->_basePath))
9292 throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
9295 public function getBaseUrl()
9297 if($this->_baseUrl===null)
9299 $appPath=dirname($this->getRequest()->getApplicationFilePath());
9300 $basePath=$this->getBasePath();
9301 if(strpos($basePath,$appPath)===false)
9302 throw new TConfigurationException('thememanager_baseurl_required');
9303 $appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
9304 $this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
9306 return $this->_baseUrl;
9308 public function setBaseUrl($value)
9310 $this->_baseUrl=rtrim($value,'/');
9313 class TTheme extends TApplicationComponent implements ITheme
9315 const THEME_CACHE_PREFIX='prado:theme:';
9316 const SKIN_FILE_EXT='.skin';
9317 private $_themePath;
9319 private $_skins=null;
9321 private $_cssFiles=array();
9322 private $_jsFiles=array();
9323 public function __construct($themePath,$themeUrl)
9325 $this->_themeUrl=$themeUrl;
9326 $this->_themePath=realpath($themePath);
9327 $this->_name=basename($themePath);
9329 if(($cache=$this->getApplication()->getCache())!==null)
9331 $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
9332 if(is_array($array))
9334 list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
9335 if($this->getApplication()->getMode()!==TApplicationMode::Performance)
9337 if(($dir=opendir($themePath))===false)
9338 throw new TIOException('theme_path_inexistent',$themePath);
9340 while(($file=readdir($dir))!==false)
9342 if($file==='.' || $file==='..')
9344 else if(basename($file,'.css')!==$file)
9345 $this->_cssFiles[]=$themeUrl.'/'.$file;
9346 else if(basename($file,'.js')!==$file)
9347 $this->_jsFiles[]=$themeUrl.'/'.$file;
9348 else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
9356 $this->_skins=$skins;
9361 $this->_cssFiles=$cssFiles;
9362 $this->_jsFiles=$jsFiles;
9363 $this->_skins=$skins;
9369 $this->_cssFiles=array();
9370 $this->_jsFiles=array();
9371 $this->_skins=array();
9372 if(($dir=opendir($themePath))===false)
9373 throw new TIOException('theme_path_inexistent',$themePath);
9374 while(($file=readdir($dir))!==false)
9376 if($file==='.' || $file==='..')
9378 else if(basename($file,'.css')!==$file)
9379 $this->_cssFiles[]=$themeUrl.'/'.$file;
9380 else if(basename($file,'.js')!==$file)
9381 $this->_jsFiles[]=$themeUrl.'/'.$file;
9382 else if(basename($file,self::SKIN_FILE_EXT)!==$file)
9384 $template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
9385 foreach($template->getItems() as $skin)
9387 if(!isset($skin[2])) continue;
9388 else if($skin[0]!==-1)
9389 throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
9391 $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
9392 unset($skin[2]['skinid']);
9393 if(isset($this->_skins[$type][$id]))
9394 throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
9395 $this->_skins[$type][$id]=$skin[2];
9400 sort($this->_cssFiles);
9401 sort($this->_jsFiles);
9403 $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
9406 public function getName()
9408 return $this->_name;
9410 protected function setName($value)
9412 $this->_name = $value;
9414 public function getBaseUrl()
9416 return $this->_themeUrl;
9418 protected function setBaseUrl($value)
9420 $this->_themeUrl=rtrim($value,'/');
9422 public function getBasePath()
9424 return $this->_themePath;
9426 protected function setBasePath($value)
9428 $this->_themePath=$value;
9430 public function getSkins()
9432 return $this->_skins;
9434 protected function setSkins($value)
9436 $this->_skins = $value;
9438 public function applySkin($control)
9440 $type=get_class($control);
9441 if(($id=$control->getSkinID())==='')
9443 if(isset($this->_skins[$type][$id]))
9445 foreach($this->_skins[$type][$id] as $name=>$value)
9447 if(is_array($value))
9451 case TTemplate::CONFIG_EXPRESSION:
9452 $value=$this->evaluateExpression($value[1]);
9454 case TTemplate::CONFIG_ASSET:
9455 $value=$this->_themeUrl.'/'.ltrim($value[1],'/');
9457 case TTemplate::CONFIG_DATABIND:
9458 $control->bindProperty($name,$value[1]);
9460 case TTemplate::CONFIG_PARAMETER:
9461 $control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
9463 case TTemplate::CONFIG_TEMPLATE:
9464 $control->setSubProperty($name,$value[1]);
9466 case TTemplate::CONFIG_LOCALIZATION:
9467 $control->setSubProperty($name,Prado::localize($value[1]));
9470 throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
9474 if(!is_array($value))
9476 if(strpos($name,'.')===false) {
9477 if($control->hasProperty($name))
9479 if($control->canSetProperty($name))
9481 $setter='set'.$name;
9482 $control->$setter($value);
9485 throw new TConfigurationException('theme_property_readonly',$type,$name);
9488 throw new TConfigurationException('theme_property_undefined',$type,$name);
9490 else $control->setSubProperty($name,$value);
9498 public function getStyleSheetFiles()
9500 return $this->_cssFiles;
9502 protected function setStyleSheetFiles($value)
9504 $this->_cssFiles=$value;
9506 public function getJavaScriptFiles()
9508 return $this->_jsFiles;
9510 protected function setJavaScriptFiles($value)
9512 $this->_jsFiles=$value;
9515 class TPageService extends TService
9517 const CONFIG_FILE_XML='config.xml';
9518 const CONFIG_FILE_PHP='config.php';
9519 const DEFAULT_BASEPATH='Pages';
9520 const FALLBACK_BASEPATH='pages';
9521 const CONFIG_CACHE_PREFIX='prado:pageservice:';
9522 const PAGE_FILE_EXT='.page';
9523 private $_basePath=null;
9524 private $_basePageClass='TPage';
9525 private $_clientScriptManagerClass='System.Web.UI.TClientScriptManager';
9526 private $_defaultPage='Home';
9527 private $_pagePath=null;
9528 private $_page=null;
9529 private $_properties=array();
9530 private $_initialized=false;
9531 private $_themeManager=null;
9532 private $_templateManager=null;
9533 public function init($config)
9535 $pageConfig=$this->loadPageConfig($config);
9536 $this->initPageContext($pageConfig);
9537 $this->_initialized=true;
9539 protected function initPageContext($pageConfig)
9541 $application=$this->getApplication();
9542 foreach($pageConfig->getApplicationConfigurations() as $appConfig)
9543 $application->applyConfiguration($appConfig);
9544 $this->applyConfiguration($pageConfig);
9546 protected function applyConfiguration($config)
9548 $this->_properties=array_merge($this->_properties, $config->getProperties());
9549 $this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
9550 $pagePath=$this->getRequestedPagePath();
9551 foreach($config->getExternalConfigurations() as $filePath=>$params)
9553 list($configPagePath,$condition)=$params;
9554 if($condition!==true)
9555 $condition=$this->evaluateExpression($condition);
9558 if(($path=Prado::getPathOfNamespace($filePath,Prado::getApplication()->getConfigurationFileExt()))===null || !is_file($path))
9559 throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
9560 $c=new TPageConfiguration($pagePath);
9561 $c->loadFromFile($path,$configPagePath);
9562 $this->applyConfiguration($c);
9566 protected function determineRequestedPagePath()
9568 $pagePath=$this->getRequest()->getServiceParameter();
9569 if(empty($pagePath))
9570 $pagePath=$this->getDefaultPage();
9573 protected function loadPageConfig($config)
9575 $application=$this->getApplication();
9576 $pagePath=$this->getRequestedPagePath();
9577 if(($cache=$application->getCache())===null)
9579 $pageConfig=new TPageConfiguration($pagePath);
9582 if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9583 $pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9585 $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9587 $pageConfig->loadFromFiles($this->getBasePath());
9592 $currentTimestamp=array();
9593 $arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
9596 list($pageConfig,$timestamps)=$arr;
9597 if($application->getMode()!==TApplicationMode::Performance)
9599 foreach($timestamps as $fileName=>$timestamp)
9602 $appConfigFile=$application->getConfigurationFile();
9603 $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9604 if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
9605 $configCached=false;
9609 $currentTimestamp[$fileName]=@filemtime($fileName);
9610 if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
9611 $configCached=false;
9618 $configCached=false;
9619 $paths=explode('.',$pagePath);
9620 $configPath=$this->getBasePath();
9621 $fileName = $this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9622 ? self::CONFIG_FILE_PHP
9623 : self::CONFIG_FILE_XML;
9624 foreach($paths as $path)
9626 $configFile=$configPath.DIRECTORY_SEPARATOR.$fileName;
9627 $currentTimestamp[$configFile]=@filemtime($configFile);
9628 $configPath.=DIRECTORY_SEPARATOR.$path;
9630 $appConfigFile=$application->getConfigurationFile();
9631 $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9635 $pageConfig=new TPageConfiguration($pagePath);
9638 if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9639 $pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9641 $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9643 $pageConfig->loadFromFiles($this->getBasePath());
9644 $cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
9649 public function getTemplateManager()
9651 if(!$this->_templateManager)
9653 $this->_templateManager=new TTemplateManager;
9654 $this->_templateManager->init(null);
9656 return $this->_templateManager;
9658 public function setTemplateManager(TTemplateManager $value)
9660 $this->_templateManager=$value;
9662 public function getThemeManager()
9664 if(!$this->_themeManager)
9666 $this->_themeManager=new TThemeManager;
9667 $this->_themeManager->init(null);
9669 return $this->_themeManager;
9671 public function setThemeManager(TThemeManager $value)
9673 $this->_themeManager=$value;
9675 public function getRequestedPagePath()
9677 if($this->_pagePath===null)
9679 $this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
9680 if(empty($this->_pagePath))
9681 throw new THttpException(404,'pageservice_page_required');
9683 return $this->_pagePath;
9685 public function getRequestedPage()
9687 return $this->_page;
9689 public function getDefaultPage()
9691 return $this->_defaultPage;
9693 public function setDefaultPage($value)
9695 if($this->_initialized)
9696 throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
9698 $this->_defaultPage=$value;
9700 public function getDefaultPageUrl()
9702 return $this->constructUrl($this->getDefaultPage());
9704 public function getBasePath()
9706 if($this->_basePath===null)
9708 $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9709 if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9711 $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::FALLBACK_BASEPATH;
9712 if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9713 throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
9716 return $this->_basePath;
9718 public function setBasePath($value)
9720 if($this->_initialized)
9721 throw new TInvalidOperationException('pageservice_basepath_unchangeable');
9722 else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
9723 throw new TConfigurationException('pageservice_basepath_invalid',$value);
9724 $this->_basePath=realpath($path);
9726 public function setBasePageClass($value)
9728 $this->_basePageClass=$value;
9730 public function getBasePageClass()
9732 return $this->_basePageClass;
9734 public function setClientScriptManagerClass($value)
9736 $this->_clientScriptManagerClass=$value;
9738 public function getClientScriptManagerClass()
9740 return $this->_clientScriptManagerClass;
9742 public function run()
9744 $this->_page=$this->createPage($this->getRequestedPagePath());
9745 $this->runPage($this->_page,$this->_properties);
9747 protected function createPage($pagePath)
9749 $path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
9750 $hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
9751 $hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
9752 if(!$hasTemplateFile && !$hasClassFile)
9753 throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9756 $className=basename($path);
9757 if(!class_exists($className,false))
9758 include_once($path.Prado::CLASS_FILE_EXT);
9762 $className=$this->getBasePageClass();
9763 Prado::using($className);
9764 if(($pos=strrpos($className,'.'))!==false)
9765 $className=substr($className,$pos+1);
9767 if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
9768 throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9769 $page=Prado::createComponent($className);
9770 $page->setPagePath($pagePath);
9771 if($hasTemplateFile)
9772 $page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
9775 protected function runPage($page,$properties)
9777 foreach($properties as $name=>$value)
9778 $page->setSubProperty($name,$value);
9779 $page->run($this->getResponse()->createHtmlWriter());
9781 public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
9783 return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
9786 class TPageConfiguration extends TComponent
9788 private $_appConfigs=array();
9789 private $_properties=array();
9790 private $_rules=array();
9791 private $_includes=array();
9792 private $_pagePath='';
9793 public function __construct($pagePath)
9795 $this->_pagePath=$pagePath;
9797 public function getExternalConfigurations()
9799 return $this->_includes;
9801 public function getProperties()
9803 return $this->_properties;
9805 public function getRules()
9807 return $this->_rules;
9809 public function getApplicationConfigurations()
9811 return $this->_appConfigs;
9813 public function loadFromFiles($basePath)
9815 $paths=explode('.',$this->_pagePath);
9816 $page=array_pop($paths);
9819 $fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9820 ? TPageService::CONFIG_FILE_PHP
9821 : TPageService::CONFIG_FILE_XML;
9822 foreach($paths as $p)
9824 $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9825 $path.=DIRECTORY_SEPARATOR.$p;
9826 if($configPagePath==='')
9829 $configPagePath.='.'.$p;
9831 $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9832 $this->_rules=new TAuthorizationRuleCollection($this->_rules);
9834 public function loadFromFile($fname,$configPagePath)
9836 if(empty($fname) || !is_file($fname))
9838 if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9840 $fcontent = include $fname;
9841 $this->loadFromPhp($fcontent,dirname($fname),$configPagePath);
9845 $dom=new TXmlDocument;
9846 if($dom->loadFromFile($fname))
9847 $this->loadFromXml($dom,dirname($fname),$configPagePath);
9849 throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
9852 public function loadFromPhp($config,$configPath,$configPagePath)
9854 $this->loadApplicationConfigurationFromPhp($config,$configPath);
9855 $this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath);
9857 public function loadFromXml($dom,$configPath,$configPagePath)
9859 $this->loadApplicationConfigurationFromXml($dom,$configPath);
9860 $this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
9862 public function loadApplicationConfigurationFromPhp($config,$configPath)
9864 $appConfig=new TApplicationConfiguration;
9865 $appConfig->loadFromPhp($config,$configPath);
9866 $this->_appConfigs[]=$appConfig;
9868 public function loadApplicationConfigurationFromXml($dom,$configPath)
9870 $appConfig=new TApplicationConfiguration;
9871 $appConfig->loadFromXml($dom,$configPath);
9872 $this->_appConfigs[]=$appConfig;
9874 public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath)
9876 if(isset($config['authorization']) && is_array($config['authorization']))
9879 foreach($config['authorization'] as $authorization)
9881 $patterns=isset($authorization['pages'])?$authorization['pages']:'';
9883 if(empty($patterns) || trim($patterns)==='*') $ruleApplies=true;
9886 foreach(explode(',',$patterns) as $pattern)
9888 if(($pattern=trim($pattern))!=='')
9890 if($configPagePath!=='') $pattern=$configPagePath.'.'.$pattern;
9891 if(strcasecmp($pattern,$this->_pagePath)===0)
9896 if($pattern[strlen($pattern)-1]==='*') {
9897 if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9908 $action = isset($authorization['action'])?$authorization['action']:'';
9909 $users = isset($authorization['users'])?$authorization['users']:'';
9910 $roles = isset($authorization['roles'])?$authorization['roles']:'';
9911 $verb = isset($authorization['verb'])?$authorization['verb']:'';
9912 $ips = isset($authorization['ips'])?$authorization['ips']:'';
9913 $rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips);
9916 $this->_rules=array_merge($rules,$this->_rules);
9918 if(isset($config['pages']) && is_array($config['pages']))
9920 if(isset($config['pages']['properties']))
9922 $this->_properties = array_merge($this->_properties, $config['pages']['properties']);
9923 unset($config['pages']['properties']);
9925 foreach($config['pages'] as $id => $page)
9927 $properties = array();
9928 if(isset($page['properties']))
9930 $properties=$page['properties'];
9931 unset($page['properties']);
9934 $id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
9935 if(strcasecmp($id,$this->_pagePath)===0)
9937 else if($id[strlen($id)-1]==='*') $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
9939 $this->_properties=array_merge($this->_properties,$properties);
9942 if(isset($config['includes']) && is_array($config['includes']))
9944 foreach($config['includes'] as $include)
9946 $when = isset($include['when'])?true:false;
9947 if(!isset($include['file']))
9948 throw new TConfigurationException('pageserviceconf_includefile_required');
9949 $filePath = $include['file'];
9950 if(isset($this->_includes[$filePath]))
9951 $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
9953 $this->_includes[$filePath]=array($configPagePath,$when);
9957 public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
9959 if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
9962 foreach($authorizationNode->getElements() as $node)
9964 $patterns=$node->getAttribute('pages');
9966 if(empty($patterns) || trim($patterns)==='*') $ruleApplies=true;
9969 foreach(explode(',',$patterns) as $pattern)
9971 if(($pattern=trim($pattern))!=='')
9973 if($configPagePath!=='') $pattern=$configPagePath.'.'.$pattern;
9974 if(strcasecmp($pattern,$this->_pagePath)===0)
9979 if($pattern[strlen($pattern)-1]==='*') {
9980 if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9990 $rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
9992 $this->_rules=array_merge($rules,$this->_rules);
9994 if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
9996 $this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
9997 foreach($pagesNode->getElementsByTagName('page') as $node)
9999 $properties=$node->getAttributes();
10000 $id=$properties->remove('id');
10002 throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
10004 $id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
10005 if(strcasecmp($id,$this->_pagePath)===0)
10007 else if($id[strlen($id)-1]==='*') $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
10009 $this->_properties=array_merge($this->_properties,$properties->toArray());
10012 foreach($dom->getElementsByTagName('include') as $node)
10014 if(($when=$node->getAttribute('when'))===null)
10016 if(($filePath=$node->getAttribute('file'))===null)
10017 throw new TConfigurationException('pageserviceconf_includefile_required');
10018 if(isset($this->_includes[$filePath]))
10019 $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
10021 $this->_includes[$filePath]=array($configPagePath,$when);
10025 class TAssetManager extends TModule
10027 const DEFAULT_BASEPATH='assets';
10028 private $_basePath=null;
10029 private $_baseUrl=null;
10030 private $_checkTimestamp=false;
10031 private $_application;
10032 private $_published=array();
10033 private $_initialized=false;
10034 public function init($config)
10036 $application=$this->getApplication();
10037 if($this->_basePath===null)
10038 $this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
10039 if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
10040 throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
10041 if($this->_baseUrl===null)
10042 $this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
10043 $application->setAssetManager($this);
10044 $this->_initialized=true;
10046 public function getBasePath()
10048 return $this->_basePath;
10050 public function setBasePath($value)
10052 if($this->_initialized)
10053 throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
10056 $this->_basePath=Prado::getPathOfNamespace($value);
10057 if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
10058 throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value);
10061 public function getBaseUrl()
10063 return $this->_baseUrl;
10065 public function setBaseUrl($value)
10067 if($this->_initialized)
10068 throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
10070 $this->_baseUrl=rtrim($value,'/');
10072 public function publishFilePath($path,$checkTimestamp=false)
10074 if(isset($this->_published[$path]))
10075 return $this->_published[$path];
10076 else if(empty($path) || ($fullpath=realpath($path))===false)
10077 throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
10078 else if(is_file($fullpath))
10080 $dir=$this->hash(dirname($fullpath));
10081 $fileName=basename($fullpath);
10082 $dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
10083 if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10084 $this->copyFile($fullpath,$dst);
10085 return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
10089 $dir=$this->hash($fullpath);
10090 if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10092 $this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
10094 return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
10097 public function getPublished()
10099 return $this->_published;
10101 protected function setPublished($values=array())
10103 $this->_published = $values;
10105 public function getPublishedPath($path)
10107 $path=realpath($path);
10109 return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
10111 return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
10113 public function getPublishedUrl($path)
10115 $path=realpath($path);
10117 return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
10119 return $this->_baseUrl.'/'.$this->hash($path);
10121 protected function hash($dir)
10123 return sprintf('%x',crc32($dir.Prado::getVersion()));
10125 protected function copyFile($src,$dst)
10130 @chmod($dst, PRADO_CHMOD);
10132 $dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
10133 if(@filemtime($dstFile)<@filemtime($src))
10135 @copy($src,$dstFile);
10138 public function copyDirectory($src,$dst)
10143 @chmod($dst, PRADO_CHMOD);
10145 if($folder=@opendir($src))
10147 while($file=@readdir($folder))
10149 if($file==='.' || $file==='..' || $file==='.svn')
10151 else if(is_file($src.DIRECTORY_SEPARATOR.$file))
10153 if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
10155 @copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10156 @chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
10160 $this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10164 throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
10167 public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
10169 if(isset($this->_published[$md5sum]))
10170 return $this->_published[$md5sum];
10171 else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
10172 throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
10175 $dir=$this->hash(dirname($fullpath));
10176 $fileName=basename($fullpath);
10177 $dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
10178 if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10180 if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
10182 $this->copyFile($fullpath,$dst);
10183 $this->deployTarFile($tarfile,$dst);
10186 return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
10189 protected function deployTarFile($path,$destination)
10191 if(($fullpath=realpath($path))===false || !is_file($fullpath))
10192 throw new TIOException('assetmanager_tarfile_invalid',$path);
10195 Prado::using('System.IO.TTarFileExtractor');
10196 $tar = new TTarFileExtractor($fullpath);
10197 return $tar->extract($destination);
10201 class TGlobalization extends TModule
10203 private $_defaultCharset = 'UTF-8';
10204 private $_defaultCulture = 'en';
10205 private $_charset=null;
10206 private $_culture=null;
10207 private $_translation;
10208 private $_translateDefaultCulture=true;
10209 public function init($config)
10211 if($this->_charset===null)
10212 $this->_charset=$this->getDefaultCharset();
10213 if($this->_culture===null)
10214 $this->_culture=$this->getDefaultCulture();
10217 if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10218 $translation = isset($config['translate'])?$config['translate']:null;
10221 $t = $config->getElementByTagName('translation');
10222 $translation = ($t)?$t->getAttributes():null;
10225 $this->setTranslationConfiguration($translation);
10227 $this->getApplication()->setGlobalization($this);
10229 public function getTranslateDefaultCulture()
10231 return $this->_translateDefaultCulture;
10233 public function setTranslateDefaultCulture($value)
10235 $this->_translateDefaultCulture = TPropertyValue::ensureBoolean($value);
10237 public function getDefaultCulture()
10239 return $this->_defaultCulture;
10241 public function setDefaultCulture($culture)
10243 $this->_defaultCulture = str_replace('-','_',$culture);
10245 public function getDefaultCharset()
10247 return $this->_defaultCharset;
10249 public function setDefaultCharset($charset)
10251 $this->_defaultCharset = $charset;
10253 public function getCulture()
10255 return $this->_culture;
10257 public function setCulture($culture)
10259 $this->_culture = str_replace('-','_',$culture);
10261 public function getCharset()
10263 return $this->_charset;
10265 public function setCharset($charset)
10267 $this->_charset = $charset;
10269 public function getTranslationConfiguration()
10271 return (!$this->_translateDefaultCulture && ($this->getDefaultCulture() == $this->getCulture()))
10273 : $this->_translation;
10275 protected function setTranslationConfiguration($config)
10277 if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
10279 if($config['source'])
10281 $config['source'] = Prado::getPathOfNamespace($config['source']);
10282 if(!is_dir($config['source']))
10284 if(@mkdir($config['source'])===false)
10285 throw new TConfigurationException('globalization_source_path_failed',
10286 $config['source']);
10287 chmod($config['source'], PRADO_CHMOD); }
10291 throw new TConfigurationException("invalid source dir '{$config['source']}'");
10294 if(isset($config['cache']) && TPropertyValue::ensureBoolean($config['cache']))
10296 $config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
10297 if(!is_dir($config['cache']))
10299 if(@mkdir($config['cache'])===false)
10300 throw new TConfigurationException('globalization_cache_path_failed',
10302 chmod($config['cache'], PRADO_CHMOD); }
10306 unset($config['cache']);
10308 $this->_translation = $config;
10310 public function getTranslationCatalogue()
10312 return $this->_translation['catalogue'];
10314 public function setTranslationCatalogue($value)
10316 $this->_translation['catalogue'] = $value;
10318 public function getCultureVariants($culture=null)
10320 if($culture===null) $culture = $this->getCulture();
10321 $variants = explode('_', $culture);
10323 for(; count($variants) > 0; array_pop($variants))
10324 $result[] = implode('_', $variants);
10327 public function getLocalizedResource($file,$culture=null)
10330 $variants = $this->getCultureVariants($culture);
10331 $path = pathinfo($file);
10332 foreach($variants as $variant)
10333 $files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename'];
10334 $filename = substr($path['basename'],0,strrpos($path['basename'],'.'));
10335 foreach($variants as $variant)
10336 $files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension'];
10341 class TApplication extends TComponent
10343 const STATE_OFF='Off';
10344 const STATE_DEBUG='Debug';
10345 const STATE_NORMAL='Normal';
10346 const STATE_PERFORMANCE='Performance';
10347 const PAGE_SERVICE_ID='page';
10348 const CONFIG_FILE_XML='application.xml';
10349 const CONFIG_FILE_EXT_XML='.xml';
10350 const CONFIG_TYPE_XML = 'xml';
10351 const CONFIG_FILE_PHP='application.php';
10352 const CONFIG_FILE_EXT_PHP='.php';
10353 const CONFIG_TYPE_PHP = 'php';
10354 const RUNTIME_PATH='runtime';
10355 const CONFIGCACHE_FILE='config.cache';
10356 const GLOBAL_FILE='global.cache';
10357 private static $_steps=array(
10360 'onLoadStateComplete',
10361 'onAuthentication',
10362 'onAuthenticationComplete',
10364 'onAuthorizationComplete',
10368 'onSaveStateComplete',
10369 'onPreFlushOutput',
10373 private $_uniqueID;
10374 private $_requestCompleted=false;
10376 private $_services;
10378 private $_modules=array();
10379 private $_lazyModules=array();
10380 private $_parameters;
10381 private $_configFile;
10382 private $_configFileExt;
10383 private $_configType;
10384 private $_basePath;
10385 private $_runtimePath;
10386 private $_stateChanged=false;
10387 private $_globals=array();
10388 private $_cacheFile;
10389 private $_errorHandler;
10391 private $_response;
10394 private $_statePersister;
10396 private $_globalization;
10397 private $_security;
10398 private $_assetManager;
10399 private $_authRules;
10400 private $_mode=TApplicationMode::Debug;
10401 private $_pageServiceID = self::PAGE_SERVICE_ID;
10402 public function __construct($basePath='protected',$cacheConfig=true, $configType=self::CONFIG_TYPE_XML)
10404 Prado::setApplication($this);
10405 $this->setConfigurationType($configType);
10406 $this->resolvePaths($basePath);
10408 $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10409 $this->_uniqueID=md5($this->_runtimePath);
10410 $this->_parameters=new TMap;
10411 $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10412 Prado::setPathOfAlias('Application',$this->_basePath);
10414 protected function resolvePaths($basePath)
10416 if(empty($basePath) || ($basePath=realpath($basePath))===false)
10417 throw new TConfigurationException('application_basepath_invalid',$basePath);
10418 if(is_dir($basePath) && is_file($basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName()))
10419 $configFile=$basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName();
10420 else if(is_file($basePath))
10422 $configFile=$basePath;
10423 $basePath=dirname($configFile);
10427 $runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
10428 if(is_writable($runtimePath))
10430 if($configFile!==null)
10432 $runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
10433 if(!is_dir($runtimePath))
10435 if(@mkdir($runtimePath)===false)
10436 throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
10437 @chmod($runtimePath, PRADO_CHMOD); }
10438 $this->setConfigurationFile($configFile);
10440 $this->setBasePath($basePath);
10441 $this->setRuntimePath($runtimePath);
10444 throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
10446 public function run()
10450 $this->initApplication();
10451 $n=count(self::$_steps);
10453 $this->_requestCompleted=false;
10454 while($this->_step<$n)
10456 if($this->_mode===self::STATE_OFF)
10457 throw new THttpException(503,'application_unavailable');
10458 if($this->_requestCompleted)
10460 $method=self::$_steps[$this->_step];
10465 catch(Exception $e)
10467 $this->onError($e);
10469 $this->onEndRequest();
10471 public function completeRequest()
10473 $this->_requestCompleted=true;
10475 public function getRequestCompleted()
10477 return $this->_requestCompleted;
10479 public function getGlobalState($key,$defaultValue=null)
10481 return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
10483 public function setGlobalState($key,$value,$defaultValue=null,$forceSave=false)
10485 $this->_stateChanged=true;
10486 if($value===$defaultValue)
10487 unset($this->_globals[$key]);
10489 $this->_globals[$key]=$value;
10491 $this->saveGlobals();
10493 public function clearGlobalState($key)
10495 $this->_stateChanged=true;
10496 unset($this->_globals[$key]);
10498 protected function loadGlobals()
10500 $this->_globals=$this->getApplicationStatePersister()->load();
10502 protected function saveGlobals()
10504 if($this->_stateChanged)
10506 $this->_stateChanged=false;
10507 $this->getApplicationStatePersister()->save($this->_globals);
10510 public function getID()
10514 public function setID($value)
10518 public function getPageServiceID()
10520 return $this->_pageServiceID;
10522 public function setPageServiceID($value)
10524 $this->_pageServiceID=$value;
10526 public function getUniqueID()
10528 return $this->_uniqueID;
10530 public function getMode()
10532 return $this->_mode;
10534 public function setMode($value)
10536 $this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
10538 public function getBasePath()
10540 return $this->_basePath;
10542 public function setBasePath($value)
10544 $this->_basePath=$value;
10546 public function getConfigurationFile()
10548 return $this->_configFile;
10550 public function setConfigurationFile($value)
10552 $this->_configFile=$value;
10554 public function getConfigurationType()
10556 return $this->_configType;
10558 public function setConfigurationType($value)
10560 $this->_configType = $value;
10562 public function getConfigurationFileExt()
10564 if($this->_configFileExt===null)
10566 switch($this->_configType)
10568 case TApplication::CONFIG_TYPE_PHP:
10569 $this->_configFileExt = TApplication::CONFIG_FILE_EXT_PHP;
10572 $this->_configFileExt = TApplication::CONFIG_FILE_EXT_XML;
10575 return $this->_configFileExt;
10577 public function getConfigurationFileName()
10580 if($fileName == null)
10582 switch($this->_configType)
10584 case TApplication::CONFIG_TYPE_PHP:
10585 $fileName = TApplication::CONFIG_FILE_PHP;
10588 $fileName = TApplication::CONFIG_FILE_XML;
10593 public function getRuntimePath()
10595 return $this->_runtimePath;
10597 public function setRuntimePath($value)
10599 $this->_runtimePath=$value;
10600 if($this->_cacheFile)
10601 $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10602 $this->_uniqueID=md5($this->_runtimePath);
10604 public function getService()
10606 return $this->_service;
10608 public function setService($value)
10610 $this->_service=$value;
10612 public function setModule($id,IModule $module=null)
10614 if(isset($this->_modules[$id]))
10615 throw new TConfigurationException('application_moduleid_duplicated',$id);
10617 $this->_modules[$id]=$module;
10619 public function getModule($id)
10621 if(!array_key_exists($id, $this->_modules))
10623 if($this->_modules[$id]===null)
10625 $module = $this->internalLoadModule($id, true);
10626 $module[0]->init($module[1]);
10628 return $this->_modules[$id];
10630 public function getModules()
10632 return $this->_modules;
10634 public function getParameters()
10636 return $this->_parameters;
10638 public function getRequest()
10640 if(!$this->_request)
10642 $this->_request=new THttpRequest;
10643 $this->_request->init(null);
10645 return $this->_request;
10647 public function setRequest(THttpRequest $request)
10649 $this->_request=$request;
10651 public function getResponse()
10653 if(!$this->_response)
10655 $this->_response=new THttpResponse;
10656 $this->_response->init(null);
10658 return $this->_response;
10660 public function setResponse(THttpResponse $response)
10662 $this->_response=$response;
10664 public function getSession()
10666 if(!$this->_session)
10668 $this->_session=new THttpSession;
10669 $this->_session->init(null);
10671 return $this->_session;
10673 public function setSession(THttpSession $session)
10675 $this->_session=$session;
10677 public function getErrorHandler()
10679 if(!$this->_errorHandler)
10681 $this->_errorHandler=new TErrorHandler;
10682 $this->_errorHandler->init(null);
10684 return $this->_errorHandler;
10686 public function setErrorHandler(TErrorHandler $handler)
10688 $this->_errorHandler=$handler;
10690 public function getSecurityManager()
10692 if(!$this->_security)
10694 $this->_security=new TSecurityManager;
10695 $this->_security->init(null);
10697 return $this->_security;
10699 public function setSecurityManager(TSecurityManager $sm)
10701 $this->_security=$sm;
10703 public function getAssetManager()
10705 if(!$this->_assetManager)
10707 $this->_assetManager=new TAssetManager;
10708 $this->_assetManager->init(null);
10710 return $this->_assetManager;
10712 public function setAssetManager(TAssetManager $value)
10714 $this->_assetManager=$value;
10716 public function getApplicationStatePersister()
10718 if(!$this->_statePersister)
10720 $this->_statePersister=new TApplicationStatePersister;
10721 $this->_statePersister->init(null);
10723 return $this->_statePersister;
10725 public function setApplicationStatePersister(IStatePersister $persister)
10727 $this->_statePersister=$persister;
10729 public function getCache()
10731 return $this->_cache;
10733 public function setCache(ICache $cache)
10735 $this->_cache=$cache;
10737 public function getUser()
10739 return $this->_user;
10741 public function setUser(IUser $user)
10743 $this->_user=$user;
10745 public function getGlobalization($createIfNotExists=true)
10747 if($this->_globalization===null && $createIfNotExists)
10749 $this->_globalization=new TGlobalization;
10750 $this->_globalization->init(null);
10752 return $this->_globalization;
10754 public function setGlobalization(TGlobalization $glob)
10756 $this->_globalization=$glob;
10758 public function getAuthorizationRules()
10760 if($this->_authRules===null)
10761 $this->_authRules=new TAuthorizationRuleCollection;
10762 return $this->_authRules;
10764 protected function getApplicationConfigurationClass()
10766 return 'TApplicationConfiguration';
10768 protected function internalLoadModule($id, $force=false)
10770 list($moduleClass, $initProperties, $configElement)=$this->_lazyModules[$id];
10771 if(isset($initProperties['lazy']) && $initProperties['lazy'] && !$force)
10773 $this->setModule($id, null);
10776 $module=Prado::createComponent($moduleClass);
10777 foreach($initProperties as $name=>$value)
10779 if($name==='lazy') continue;
10780 $module->setSubProperty($name,$value);
10782 $this->setModule($id,$module);
10783 $this->_lazyModules[$id]=null;
10784 return array($module,$configElement);
10786 public function applyConfiguration($config,$withinService=false)
10788 if($config->getIsEmpty())
10790 foreach($config->getAliases() as $alias=>$path)
10791 Prado::setPathOfAlias($alias,$path);
10792 foreach($config->getUsings() as $using)
10793 Prado::using($using);
10794 if(!$withinService)
10796 foreach($config->getProperties() as $name=>$value)
10797 $this->setSubProperty($name,$value);
10799 if(empty($this->_services))
10800 $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10801 foreach($config->getParameters() as $id=>$parameter)
10803 if(is_array($parameter))
10805 $component=Prado::createComponent($parameter[0]);
10806 foreach($parameter[1] as $name=>$value)
10807 $component->setSubProperty($name,$value);
10808 $this->_parameters->add($id,$component);
10811 $this->_parameters->add($id,$parameter);
10814 foreach($config->getModules() as $id=>$moduleConfig)
10816 if(!is_string($id))
10817 $id='_module'.count($this->_lazyModules);
10818 $this->_lazyModules[$id]=$moduleConfig;
10819 if($module = $this->internalLoadModule($id))
10820 $modules[]=$module;
10822 foreach($modules as $module)
10823 $module[0]->init($module[1]);
10824 foreach($config->getServices() as $serviceID=>$serviceConfig)
10825 $this->_services[$serviceID]=$serviceConfig;
10826 foreach($config->getExternalConfigurations() as $filePath=>$condition)
10828 if($condition!==true)
10829 $condition=$this->evaluateExpression($condition);
10832 if(($path=Prado::getPathOfNamespace($filePath,$this->getConfigurationFileExt()))===null || !is_file($path))
10833 throw new TConfigurationException('application_includefile_invalid',$filePath);
10834 $cn=$this->getApplicationConfigurationClass();
10836 $c->loadFromFile($path);
10837 $this->applyConfiguration($c,$withinService);
10841 protected function initApplication()
10843 if($this->_configFile!==null)
10845 if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
10847 $config=new TApplicationConfiguration;
10848 $config->loadFromFile($this->_configFile);
10849 if($this->_cacheFile!==null)
10850 file_put_contents($this->_cacheFile,serialize($config),LOCK_EX);
10853 $config=unserialize(file_get_contents($this->_cacheFile));
10854 $this->applyConfiguration($config,false);
10856 if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
10857 $serviceID=$this->getPageServiceID();
10858 $this->startService($serviceID);
10860 public function startService($serviceID)
10862 if(isset($this->_services[$serviceID]))
10864 list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
10865 $service=Prado::createComponent($serviceClass);
10866 if(!($service instanceof IService))
10867 throw new THttpException(500,'application_service_invalid',$serviceClass);
10868 if(!$service->getEnabled())
10869 throw new THttpException(500,'application_service_unavailable',$serviceClass);
10870 $service->setID($serviceID);
10871 $this->setService($service);
10872 foreach($initProperties as $name=>$value)
10873 $service->setSubProperty($name,$value);
10874 if($configElement!==null)
10876 $config=new TApplicationConfiguration;
10877 if($this->getConfigurationType()==self::CONFIG_TYPE_PHP)
10878 $config->loadFromPhp($configElement,$this->getBasePath());
10880 $config->loadFromXml($configElement,$this->getBasePath());
10881 $this->applyConfiguration($config,true);
10883 $service->init($configElement);
10886 throw new THttpException(500,'application_service_unknown',$serviceID);
10888 public function onError($param)
10890 Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
10891 $this->raiseEvent('OnError',$this,$param);
10892 $this->getErrorHandler()->handleError($this,$param);
10894 public function onBeginRequest()
10896 $this->raiseEvent('OnBeginRequest',$this,null);
10898 public function onAuthentication()
10900 $this->raiseEvent('OnAuthentication',$this,null);
10902 public function onAuthenticationComplete()
10904 $this->raiseEvent('OnAuthenticationComplete',$this,null);
10906 public function onAuthorization()
10908 $this->raiseEvent('OnAuthorization',$this,null);
10910 public function onAuthorizationComplete()
10912 $this->raiseEvent('OnAuthorizationComplete',$this,null);
10914 public function onLoadState()
10916 $this->loadGlobals();
10917 $this->raiseEvent('OnLoadState',$this,null);
10919 public function onLoadStateComplete()
10921 $this->raiseEvent('OnLoadStateComplete',$this,null);
10923 public function onPreRunService()
10925 $this->raiseEvent('OnPreRunService',$this,null);
10927 public function runService()
10929 if($this->_service)
10930 $this->_service->run();
10932 public function onSaveState()
10934 $this->raiseEvent('OnSaveState',$this,null);
10935 $this->saveGlobals();
10937 public function onSaveStateComplete()
10939 $this->raiseEvent('OnSaveStateComplete',$this,null);
10941 public function onPreFlushOutput()
10943 $this->raiseEvent('OnPreFlushOutput',$this,null);
10945 public function flushOutput($continueBuffering = true)
10947 $this->getResponse()->flush($continueBuffering);
10949 public function onEndRequest()
10951 $this->flushOutput(false); $this->saveGlobals(); $this->raiseEvent('OnEndRequest',$this,null);
10954 class TApplicationMode extends TEnumerable
10957 const Debug='Debug';
10958 const Normal='Normal';
10959 const Performance='Performance';
10961 class TApplicationConfiguration extends TComponent
10963 private $_properties=array();
10964 private $_usings=array();
10965 private $_aliases=array();
10966 private $_modules=array();
10967 private $_services=array();
10968 private $_parameters=array();
10969 private $_includes=array();
10970 private $_empty=true;
10971 public function loadFromFile($fname)
10973 if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10975 $fcontent = include $fname;
10976 $this->loadFromPhp($fcontent,dirname($fname));
10980 $dom=new TXmlDocument;
10981 $dom->loadFromFile($fname);
10982 $this->loadFromXml($dom,dirname($fname));
10985 public function getIsEmpty()
10987 return $this->_empty;
10989 public function loadFromPhp($config, $configPath)
10991 if(isset($config['application']))
10993 foreach($config['application'] as $name=>$value)
10995 $this->_properties[$name]=$value;
10997 $this->_empty = false;
10999 if(isset($config['paths']) && is_array($config['paths']))
11000 $this->loadPathsPhp($config['paths'],$configPath);
11001 if(isset($config['modules']) && is_array($config['modules']))
11002 $this->loadModulesPhp($config['modules'],$configPath);
11003 if(isset($config['services']) && is_array($config['services']))
11004 $this->loadServicesPhp($config['services'],$configPath);
11005 if(isset($config['parameters']) && is_array($config['parameters']))
11006 $this->loadParametersPhp($config['parameters'], $configPath);
11007 if(isset($config['includes']) && is_array($config['includes']))
11008 $this->loadExternalXml($config['includes'],$configPath);
11010 public function loadFromXml($dom,$configPath)
11012 foreach($dom->getAttributes() as $name=>$value)
11014 $this->_properties[$name]=$value;
11015 $this->_empty=false;
11017 foreach($dom->getElements() as $element)
11019 switch($element->getTagName())
11022 $this->loadPathsXml($element,$configPath);
11025 $this->loadModulesXml($element,$configPath);
11028 $this->loadServicesXml($element,$configPath);
11031 $this->loadParametersXml($element,$configPath);
11034 $this->loadExternalXml($element,$configPath);
11041 protected function loadPathsPhp($pathsNode, $configPath)
11043 if(isset($pathsNode['aliases']) && is_array($pathsNode['aliases']))
11045 foreach($pathsNode['aliases'] as $id=>$path)
11047 $path=str_replace('\\','/',$path);
11048 if(preg_match('/^\\/|.:\\/|.:\\\\/',$path)) $p=realpath($path);
11050 $p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
11051 if($p===false || !is_dir($p))
11052 throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
11053 if(isset($this->_aliases[$id]))
11054 throw new TConfigurationException('appconfig_alias_redefined',$id);
11055 $this->_aliases[$id]=$p;
11058 if(isset($pathsNode['using']) && is_array($pathsNode['using']))
11060 foreach($pathsNode['using'] as $namespace)
11062 $this->_usings[] = $namespace;
11066 protected function loadPathsXml($pathsNode,$configPath)
11068 foreach($pathsNode->getElements() as $element)
11070 switch($element->getTagName())
11074 if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
11076 $path=str_replace('\\','/',$path);
11077 if(preg_match('/^\\/|.:\\/|.:\\\\/',$path)) $p=realpath($path);
11079 $p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
11080 if($p===false || !is_dir($p))
11081 throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
11082 if(isset($this->_aliases[$id]))
11083 throw new TConfigurationException('appconfig_alias_redefined',$id);
11084 $this->_aliases[$id]=$p;
11087 throw new TConfigurationException('appconfig_alias_invalid');
11088 $this->_empty=false;
11093 if(($namespace=$element->getAttribute('namespace'))!==null)
11094 $this->_usings[]=$namespace;
11096 throw new TConfigurationException('appconfig_using_invalid');
11097 $this->_empty=false;
11101 throw new TConfigurationException('appconfig_paths_invalid',$element->getTagName());
11105 protected function loadModulesPhp($modulesNode, $configPath)
11107 foreach($modulesNode as $id=>$module)
11109 if(!isset($module['class']))
11110 throw new TConfigurationException('appconfig_moduletype_required',$id);
11111 $type = $module['class'];
11112 unset($module['class']);
11113 $properties = array();
11114 if(isset($module['properties']))
11116 $properties = $module['properties'];
11117 unset($module['properties']);
11119 $properties['id'] = $id;
11120 $this->_modules[$id]=array($type,$properties,$module);
11121 $this->_empty=false;
11124 protected function loadModulesXml($modulesNode,$configPath)
11126 foreach($modulesNode->getElements() as $element)
11128 if($element->getTagName()==='module')
11130 $properties=$element->getAttributes();
11131 $id=$properties->itemAt('id');
11132 $type=$properties->remove('class');
11134 throw new TConfigurationException('appconfig_moduletype_required',$id);
11135 $element->setParent(null);
11137 $this->_modules[]=array($type,$properties->toArray(),$element);
11139 $this->_modules[$id]=array($type,$properties->toArray(),$element);
11140 $this->_empty=false;
11143 throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
11146 protected function loadServicesPhp($servicesNode,$configPath)
11148 foreach($servicesNode as $id => $service)
11150 if(!isset($service['class']))
11151 throw new TConfigurationException('appconfig_servicetype_required');
11152 $type = $service['class'];
11153 $properties = isset($service['properties']) ? $service['properties'] : array();
11154 unset($service['properties']);
11155 $properties['id'] = $id;
11156 $this->_services[$id] = array($type,$properties,$service);
11157 $this->_empty = false;
11160 protected function loadServicesXml($servicesNode,$configPath)
11162 foreach($servicesNode->getElements() as $element)
11164 if($element->getTagName()==='service')
11166 $properties=$element->getAttributes();
11167 if(($id=$properties->itemAt('id'))===null)
11168 throw new TConfigurationException('appconfig_serviceid_required');
11169 if(($type=$properties->remove('class'))===null)
11170 throw new TConfigurationException('appconfig_servicetype_required',$id);
11171 $element->setParent(null);
11172 $this->_services[$id]=array($type,$properties->toArray(),$element);
11173 $this->_empty=false;
11176 throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
11179 protected function loadParametersPhp($parametersNode,$configPath)
11181 foreach($parametersNode as $id => $parameter)
11183 if(is_array($parameter))
11185 if(isset($parameter['class']))
11187 $type = $parameter['class'];
11188 unset($parameter['class']);
11189 $properties = isset($service['properties']) ? $service['properties'] : array();
11190 $properties['id'] = $id;
11191 $this->_parameters[$id] = array($type,$properties);
11196 $this->_parameters[$id] = $parameter;
11200 protected function loadParametersXml($parametersNode,$configPath)
11202 foreach($parametersNode->getElements() as $element)
11204 if($element->getTagName()==='parameter')
11206 $properties=$element->getAttributes();
11207 if(($id=$properties->remove('id'))===null)
11208 throw new TConfigurationException('appconfig_parameterid_required');
11209 if(($type=$properties->remove('class'))===null)
11211 if(($value=$properties->remove('value'))===null)
11212 $this->_parameters[$id]=$element;
11214 $this->_parameters[$id]=$value;
11217 $this->_parameters[$id]=array($type,$properties->toArray());
11218 $this->_empty=false;
11221 throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
11224 protected function loadExternalPhp($includeNode,$configPath)
11226 foreach($includeNode as $include)
11228 $when = isset($include['when'])?true:false;
11229 if(!isset($include['file']))
11230 throw new TConfigurationException('appconfig_includefile_required');
11231 $filePath = $include['file'];
11232 if(isset($this->_includes[$filePath]))
11233 $this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11235 $$this->_includes[$filePath]=$when;
11236 $this->_empty=false;
11239 protected function loadExternalXml($includeNode,$configPath)
11241 if(($when=$includeNode->getAttribute('when'))===null)
11243 if(($filePath=$includeNode->getAttribute('file'))===null)
11244 throw new TConfigurationException('appconfig_includefile_required');
11245 if(isset($this->_includes[$filePath]))
11246 $this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11248 $this->_includes[$filePath]=$when;
11249 $this->_empty=false;
11251 public function getProperties()
11253 return $this->_properties;
11255 public function getAliases()
11257 return $this->_aliases;
11259 public function getUsings()
11261 return $this->_usings;
11263 public function getModules()
11265 return $this->_modules;
11267 public function getServices()
11269 return $this->_services;
11271 public function getParameters()
11273 return $this->_parameters;
11275 public function getExternalConfigurations()
11277 return $this->_includes;
11280 class TApplicationStatePersister extends TModule implements IStatePersister
11282 const CACHE_NAME='prado:appstate';
11283 public function init($config)
11285 $this->getApplication()->setApplicationStatePersister($this);
11287 protected function getStateFilePath()
11289 return $this->getApplication()->getRuntimePath().'/global.cache';
11291 public function load()
11293 if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
11294 return unserialize($value);
11297 if(($content=@file_get_contents($this->getStateFilePath()))!==false)
11298 return unserialize($content);
11303 public function save($state)
11305 $content=serialize($state);
11307 if(($cache=$this->getApplication()->getCache())!==null)
11309 if($cache->get(self::CACHE_NAME)===$content)
11312 $cache->set(self::CACHE_NAME,$content);
11316 $fileName=$this->getStateFilePath();
11317 file_put_contents($fileName,$content,LOCK_EX);
11321 class TShellApplication extends TApplication
11323 public function run()
11325 $this->initApplication();