]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/framework/pradolite.php
baculum: Fix sqlite db support
[bacula/bacula] / gui / baculum / framework / pradolite.php
1 <?php
2 /**
3  * File Name: pradolite.php
4  * Last Update: 2016/08/23 12:44:08
5  * Generated By: buildscripts/phpbuilder/build.php
6  *
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.
10  *
11  * Do not modify this file manually.
12  */
13
14 if(!defined('PRADO_DIR'))
15         define('PRADO_DIR',dirname(__FILE__));
16 if(!defined('PRADO_CHMOD'))
17         define('PRADO_CHMOD',0777);
18 class PradoBase
19 {
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()
27         {
28                 return '3.3.2';
29         }
30         public static function initErrorHandlers()
31         {
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);
36         }
37         public static function autoload($className)
38         {
39                 @include_once($className.self::CLASS_FILE_EXT);
40         }
41         public static function poweredByPrado($logoType=0)
42         {
43                 $logoName=$logoType==1?'powered2':'powered';
44                 if(self::$_application!==null)
45                 {
46                         $am=self::$_application->getAssetManager();
47                         $url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
48                 }
49                 else
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>';
52         }
53         public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
54         {
55                 if(error_reporting() & $errno)
56                         throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
57         }
58         public static function phpFatalErrorHandler()
59         {
60                 $error = error_get_last();
61                 if($error && 
62                         TPhpErrorException::isFatalError($error) &&
63                         error_reporting() & $error['type'])
64                 {
65                         self::exceptionHandler(new TPhpErrorException($error['type'],$error['message'],$error['file'],$error['line']));
66                 }
67         }
68         public static function exceptionHandler($exception)
69         {
70                 if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
71                 {
72                         $errorHandler->handleError(null,$exception);
73                 }
74                 else
75                 {
76                         echo $exception;
77                 }
78                 exit(1);
79         }
80         public static function setApplication($application)
81         {
82                 if(self::$_application!==null && !defined('PRADO_TEST_RUN'))
83                         throw new TInvalidOperationException('prado_application_singleton_required');
84                 self::$_application=$application;
85         }
86         public static function getApplication()
87         {
88                 return self::$_application;
89         }
90         public static function getFrameworkPath()
91         {
92                 return PRADO_DIR;
93         }
94         public static function createComponent($type)
95         {
96                 if(!isset(self::$classExists[$type]))
97                         self::$classExists[$type] = class_exists($type, false);
98                 if( !isset(self::$_usings[$type]) && !self::$classExists[$type]) {
99                         self::using($type);
100                         self::$classExists[$type] = class_exists($type, false);
101                 }
102                 if( ($pos = strrpos($type, '.')) !== false)
103                         $type = substr($type,$pos+1);
104                 if(($n=func_num_args())>1)
105                 {
106                         $args = func_get_args();
107                         switch($n) {
108                                 case 2:
109                                         return new $type($args[1]);
110                                 break;
111                                 case 3:
112                                         return new $type($args[1], $args[2]);
113                                 break;
114                                 case 4:
115                                         return new $type($args[1], $args[2], $args[3]);
116                                 break;
117                                 case 5:
118                                         return new $type($args[1], $args[2], $args[3], $args[4]);
119                                 break;
120                                 default:
121                                         $s='$args[1]';
122                                         for($i=2;$i<$n;++$i)
123                                                 $s.=",\$args[$i]";
124                                         eval("\$component=new $type($s);");
125                                         return $component;
126                                 break;
127                         }
128                 }
129                 else
130                         return new $type;
131         }
132         public static function using($namespace,$checkClassExistence=true)
133         {
134                 if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
135                         return;
136                 if(($pos=strrpos($namespace,'.'))===false)              {
137                         try
138                         {
139                                 include_once($namespace.self::CLASS_FILE_EXT);
140                         }
141                         catch(Exception $e)
142                         {
143                                 if($checkClassExistence && !class_exists($namespace,false))
144                                         throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
145                                 else
146                                         throw $e;
147                         }
148                 }
149                 else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
150                 {
151                         $className=substr($namespace,$pos+1);
152                         if($className==='*')                    {
153                                 self::$_usings[$namespace]=$path;
154                                 set_include_path(get_include_path().PATH_SEPARATOR.$path);
155                         }
156                         else                    {
157                                 self::$_usings[$namespace]=$path;
158                                 if(!$checkClassExistence || !class_exists($className,false))
159                                 {
160                                         try
161                                         {
162                                                 include_once($path);
163                                         }
164                                         catch(Exception $e)
165                                         {
166                                                 if($checkClassExistence && !class_exists($className,false))
167                                                         throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
168                                                 else
169                                                         throw $e;
170                                         }
171                                 }
172                         }
173                 }
174                 else
175                         throw new TInvalidDataValueException('prado_using_invalid',$namespace);
176         }
177         public static function getPathOfNamespace($namespace, $ext='')
178         {
179                 if(self::CLASS_FILE_EXT === $ext || empty($ext))
180                 {
181                         if(isset(self::$_usings[$namespace]))
182                                 return self::$_usings[$namespace];
183                         if(isset(self::$_aliases[$namespace]))
184                                 return self::$_aliases[$namespace];
185                 }
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);
190                 return null;
191         }
192         public static function getPathOfAlias($alias)
193         {
194                 return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
195         }
196         protected static function getPathAliases()
197         {
198                 return self::$_aliases;
199         }
200         public static function setPathOfAlias($alias,$path)
201         {
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))
205                 {
206                         if(strpos($alias,'.')===false)
207                                 self::$_aliases[$alias]=$rp;
208                         else
209                                 throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
210                 }
211                 else
212                         throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
213         }
214         public static function fatalError($msg)
215         {
216                 echo '<h1>Fatal Error</h1>';
217                 echo '<p>'.$msg.'</p>';
218                 if(!function_exists('debug_backtrace'))
219                         return;
220                 echo '<h2>Debug Backtrace</h2>';
221                 echo '<pre>';
222                 $index=-1;
223                 foreach(debug_backtrace() as $t)
224                 {
225                         $index++;
226                         if($index==0)                           continue;
227                         echo '#'.$index.' ';
228                         if(isset($t['file']))
229                                 echo basename($t['file']) . ':' . $t['line'];
230                         else
231                                  echo '<PHP inner-code>';
232                         echo ' -- ';
233                         if(isset($t['class']))
234                                 echo $t['class'] . $t['type'];
235                         echo $t['function'] . '(';
236                         if(isset($t['args']) && sizeof($t['args']) > 0)
237                         {
238                                 $count=0;
239                                 foreach($t['args'] as $item)
240                                 {
241                                         if(is_string($item))
242                                         {
243                                                 $str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
244                                                 if (strlen($item) > 70)
245                                                         echo "'". substr($str, 0, 70) . "...'";
246                                                 else
247                                                         echo "'" . $str . "'";
248                                         }
249                                         else if (is_int($item) || is_float($item))
250                                                 echo $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)
258                                                 echo 'NULL';
259                                         else if (is_resource($item))
260                                                 echo get_resource_type($item);
261                                         $count++;
262                                         if (count($t['args']) > $count)
263                                                 echo ', ';
264                                 }
265                         }
266                         echo ")\n";
267                 }
268                 echo '</pre>';
269                 exit(1);
270         }
271         public static function getUserLanguages()
272         {
273                 static $languages=null;
274                 if($languages===null)
275                 {
276                         if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
277                                 $languages[0]='en';
278                         else
279                         {
280                                 $languages=array();
281                                 foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
282                                 {
283                                         $array=explode(';q=',trim($language));
284                                         $languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
285                                 }
286                                 arsort($languages);
287                                 $languages=array_keys($languages);
288                                 if(empty($languages))
289                                         $languages[0]='en';
290                         }
291                 }
292                 return $languages;
293         }
294         public static function getPreferredLanguage()
295         {
296                 static $language=null;
297                 if($language===null)
298                 {
299                         $langs=Prado::getUserLanguages();
300                         $lang=explode('-',$langs[0]);
301                         if(empty($lang[0]) || !ctype_alpha($lang[0]))
302                                 $language='en';
303                         else
304                                 $language=$lang[0];
305                 }
306                 return $language;
307         }
308         public static function trace($msg,$category='Uncategorized',$ctl=null)
309         {
310                 if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
311                         return;
312                 if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
313                 {
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;
318                 }
319                 else
320                         $level=TLogger::INFO;
321                 self::log($msg,$level,$category,$ctl);
322         }
323         public static function log($msg,$level=TLogger::INFO,$category='Uncategorized',$ctl=null)
324         {
325                 if(self::$_logger===null)
326                         self::$_logger=new TLogger;
327                 self::$_logger->log($msg,$level,$category,$ctl);
328         }
329         public static function getLogger()
330         {
331                 if(self::$_logger===null)
332                         self::$_logger=new TLogger;
333                 return self::$_logger;
334         }
335         public static function varDump($var,$depth=10,$highlight=false)
336         {
337                 Prado::using('System.Util.TVarDumper');
338                 return TVarDumper::dump($var,$depth,$highlight);
339         }
340         public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
341         {
342                 Prado::using('System.I18N.Translation');
343                 $app = Prado::getApplication()->getGlobalization(false);
344                 $params = array();
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);
357         }
358 }
359 PradoBase::using('System.TComponent');
360 PradoBase::using('System.Exceptions.TException');
361 PradoBase::using('System.Util.TLogger');
362 if(!class_exists('Prado',false))
363 {
364         class Prado extends PradoBase
365         {
366         }
367 }
368 spl_autoload_register(array('Prado','autoload'));
369 Prado::initErrorHandlers();
370 interface IModule
371 {
372         public function init($config);
373         public function getID();
374         public function setID($id);
375 }
376 interface IService
377 {
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();
384 }
385 interface ITextWriter
386 {
387         public function write($str);
388         public function flush();
389 }
390 interface IUser
391 {
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);
401 }
402 interface IStatePersister
403 {
404         public function load();
405         public function save($state);
406 }
407 interface ICache
408 {
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();
414 }
415 interface ICacheDependency
416 {
417         public function getHasChanged();
418 }
419 interface IRenderable
420 {
421         public function render($writer);
422 }
423 interface IBindable
424 {
425         public function dataBind();
426 }
427 interface IStyleable
428 {
429         public function getHasStyle();
430         public function getStyle();
431         public function clearStyle();
432 }
433 interface IActiveControl
434 {
435         public function getActiveControl();
436 }
437 interface ICallbackEventHandler
438 {
439         public function raiseCallbackEvent($eventArgument);
440 }
441 interface IDataRenderer
442 {
443         public function getData();
444         public function setData($value);
445 }
446 class TApplicationComponent extends TComponent
447 {
448         public function getApplication()
449         {
450                 return Prado::getApplication();
451         }
452         public function getService()
453         {
454                 return Prado::getApplication()->getService();
455         }
456         public function getRequest()
457         {
458                 return Prado::getApplication()->getRequest();
459         }
460         public function getResponse()
461         {
462                 return Prado::getApplication()->getResponse();
463         }
464         public function getSession()
465         {
466                 return Prado::getApplication()->getSession();
467         }
468         public function getUser()
469         {
470                 return Prado::getApplication()->getUser();
471         }
472         public function publishAsset($assetPath,$className=null)
473         {
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);
479         }
480         public function publishFilePath($fullPath, $checkTimestamp=false)
481         {
482                 return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath, $checkTimestamp);
483         }
484 }
485 abstract class TModule extends TApplicationComponent implements IModule
486 {
487         private $_id;
488         public function init($config)
489         {
490         }
491         public function getID()
492         {
493                 return $this->_id;
494         }
495         public function setID($value)
496         {
497                 $this->_id=$value;
498         }
499 }
500 abstract class TService extends TApplicationComponent implements IService
501 {
502         private $_id;
503         private $_enabled=true;
504         public function init($config)
505         {
506         }
507         public function getID()
508         {
509                 return $this->_id;
510         }
511         public function setID($value)
512         {
513                 $this->_id=$value;
514         }
515         public function getEnabled()
516         {
517                 return $this->_enabled;
518         }
519         public function setEnabled($value)
520         {
521                 $this->_enabled=TPropertyValue::ensureBoolean($value);
522         }
523         public function run()
524         {
525         }
526 }
527 class TErrorHandler extends TModule
528 {
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)
534         {
535                 $this->getApplication()->setErrorHandler($this);
536         }
537         public function getErrorTemplatePath()
538         {
539                 if($this->_templatePath===null)
540                         $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
541                 return $this->_templatePath;
542         }
543         public function setErrorTemplatePath($value)
544         {
545                 if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath))
546                         $this->_templatePath=$templatePath;
547                 else
548                         throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value);
549         }
550         public function handleError($sender,$param)
551         {
552                 static $handling=false;
553                                                                 restore_error_handler();
554                 restore_exception_handler();
555                                 if($handling)
556                         $this->handleRecursiveError($param);
557                 else
558                 {
559                         $handling=true;
560                         if(($response=$this->getResponse())!==null)
561                                 $response->clear();
562                         if(!headers_sent())
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);
568                         else
569                                 $this->handleExternalError(500,$param);
570                 }
571         }
572         protected static function hideSecurityRelated($value, $exception=null)
573         {
574                 $aRpl = array();
575                 if($exception !== null && $exception instanceof Exception)
576                 {
577                         $aTrace = $exception->getTrace();
578                         foreach($aTrace as $item)
579                         {
580                                 if(isset($item['file']))
581                                         $aRpl[dirname($item['file']) . DIRECTORY_SEPARATOR] = '<hidden>' . DIRECTORY_SEPARATOR;
582                         }
583                 }
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);
590         }
591         protected function handleExternalError($statusCode,$exception)
592         {
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();
599                 if($isDebug)
600                         $version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
601                 else
602                 {
603                         $version='';
604                         $errorMessage = self::hideSecurityRelated($errorMessage, $exception);
605                 }
606                 $tokens=array(
607                         '%%StatusCode%%' => "$statusCode",
608                         '%%ErrorMessage%%' => htmlspecialchars($errorMessage),
609                         '%%ServerAdmin%%' => $serverAdmin,
610                         '%%Version%%' => $version,
611                         '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
612                 );
613                 $this->getApplication()->getResponse()->setStatusCode($statusCode, $isDebug ? $exception->getMessage() : null);
614                 echo strtr($content,$tokens);
615         }
616         protected function handleRecursiveError($exception)
617         {
618                 if($this->getApplication()->getMode()===TApplicationMode::Debug)
619                 {
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>";
624                 }
625                 else
626                 {
627                         error_log("Error happened while processing an existing error:\n".$exception->__toString());
628                         header('HTTP/1.0 500 Internal Error');
629                 }
630         }
631         protected function displayException($exception)
632         {
633                 if(php_sapi_name()==='cli')
634                 {
635                         echo $exception->getMessage()."\n";
636                         echo $exception->getTraceAsString();
637                         return;
638                 }
639                 if($exception instanceof TTemplateException)
640                 {
641                         $fileName=$exception->getTemplateFile();
642                         $lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
643                         $source=$this->getSourceCode($lines,$exception->getLineNumber());
644                         if($fileName==='')
645                                 $fileName='---embedded template---';
646                         $errorLine=$exception->getLineNumber();
647                 }
648                 else
649                 {
650                         if(($trace=$this->getExactTrace($exception))!==null)
651                         {
652                                 $fileName=$trace['file'];
653                                 $errorLine=$trace['line'];
654                         }
655                         else
656                         {
657                                 $fileName=$exception->getFile();
658                                 $errorLine=$exception->getLine();
659                         }
660                         $source=$this->getSourceCode(@file($fileName),$errorLine);
661                 }
662                 if($this->getApplication()->getMode()===TApplicationMode::Debug)
663                         $version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
664                 else
665                         $version='';
666                 $tokens=array(
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())
674                 );
675                 $content=$this->getExceptionTemplate($exception);
676                 echo strtr($content,$tokens);
677         }
678         protected function getExceptionTemplate($exception)
679         {
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'.");
686                 return $content;
687         }
688         protected function getErrorTemplate($statusCode,$exception)
689         {
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";
698                 else
699                         $errorFile="$base.html";
700                 if(($content=@file_get_contents($errorFile))===false)
701                         die("Unable to open error template file '$errorFile'.");
702                 return $content;
703         }
704         private function getExactTrace($exception)
705         {
706                 $trace=$exception->getTrace();
707                 $result=null;
708                                                 if($exception instanceof TPhpErrorException)
709                 {
710                         if(isset($trace[0]['file']))
711                                 $result=$trace[0];
712                         elseif(isset($trace[1]))
713                                 $result=$trace[1];
714                 }
715                 else if($exception instanceof TInvalidOperationException)
716                 {
717                                                 if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
718                                 $result=$this->getPropertyAccessTrace($trace,'__set');
719                 }
720                 if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
721                         return null;
722                 return $result;
723         }
724         private function getPropertyAccessTrace($trace,$pattern)
725         {
726                 $result=null;
727                 foreach($trace as $t)
728                 {
729                         if(isset($t['function']) && $t['function']===$pattern)
730                                 $result=$t;
731                         else
732                                 break;
733                 }
734                 return $result;
735         }
736         private function getSourceCode($lines,$errorLine)
737         {
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);
740                 $source='';
741                 for($i=$beginLine;$i<$endLine;++$i)
742                 {
743                         if($i===$errorLine-1)
744                         {
745                                 $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
746                                 $source.="<div class=\"error\">".$line."</div>";
747                         }
748                         else
749                                 $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
750                 }
751                 return $source;
752         }
753         private function addLink($message)
754         {
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);
757         }
758 }
759 class TList extends TComponent implements IteratorAggregate,ArrayAccess,Countable
760 {
761         private $_d=array();
762         private $_c=0;
763         private $_r=false;
764         public function __construct($data=null,$readOnly=false)
765         {
766                 if($data!==null)
767                         $this->copyFrom($data);
768                 $this->setReadOnly($readOnly);
769         }
770         public function getReadOnly()
771         {
772                 return $this->_r;
773         }
774         protected function setReadOnly($value)
775         {
776                 $this->_r=TPropertyValue::ensureBoolean($value);
777         }
778         public function getIterator()
779         {
780                 return new ArrayIterator( $this->_d );
781         }
782         public function count()
783         {
784                 return $this->getCount();
785         }
786         public function getCount()
787         {
788                 return $this->_c;
789         }
790         public function itemAt($index)
791         {
792                 if($index>=0 && $index<$this->_c)
793                         return $this->_d[$index];
794                 else
795                         throw new TInvalidDataValueException('list_index_invalid',$index);
796         }
797         public function add($item)
798         {
799                 $this->insertAt($this->_c,$item);
800                 return $this->_c-1;
801         }
802         public function insertAt($index,$item)
803         {
804                 if(!$this->_r)
805                 {
806                         if($index===$this->_c)
807                                 $this->_d[$this->_c++]=$item;
808                         else if($index>=0 && $index<$this->_c)
809                         {
810                                 array_splice($this->_d,$index,0,array($item));
811                                 $this->_c++;
812                         }
813                         else
814                                 throw new TInvalidDataValueException('list_index_invalid',$index);
815                 }
816                 else
817                         throw new TInvalidOperationException('list_readonly',get_class($this));
818         }
819         public function remove($item)
820         {
821                 if(!$this->_r)
822                 {
823                         if(($index=$this->indexOf($item))>=0)
824                         {
825                                 $this->removeAt($index);
826                                 return $index;
827                         }
828                         else
829                                 throw new TInvalidDataValueException('list_item_inexistent');
830                 }
831                 else
832                         throw new TInvalidOperationException('list_readonly',get_class($this));
833         }
834         public function removeAt($index)
835         {
836                 if(!$this->_r)
837                 {
838                         if($index>=0 && $index<$this->_c)
839                         {
840                                 $this->_c--;
841                                 if($index===$this->_c)
842                                         return array_pop($this->_d);
843                                 else
844                                 {
845                                         $item=$this->_d[$index];
846                                         array_splice($this->_d,$index,1);
847                                         return $item;
848                                 }
849                         }
850                         else
851                                 throw new TInvalidDataValueException('list_index_invalid',$index);
852                 }
853                 else
854                         throw new TInvalidOperationException('list_readonly',get_class($this));
855         }
856         public function clear()
857         {
858                 for($i=$this->_c-1;$i>=0;--$i)
859                         $this->removeAt($i);
860         }
861         public function contains($item)
862         {
863                 return $this->indexOf($item)>=0;
864         }
865         public function indexOf($item)
866         {
867                 if(($index=array_search($item,$this->_d,true))===false)
868                         return -1;
869                 else
870                         return $index;
871         }
872         public function insertBefore($baseitem, $item)
873         {
874                 if(!$this->_r)
875                 {
876                         if(($index = $this->indexOf($baseitem)) == -1)
877                                 throw new TInvalidDataValueException('list_item_inexistent');
878                         $this->insertAt($index, $item);
879                         return $index;
880                 }
881                 else
882                         throw new TInvalidOperationException('list_readonly',get_class($this));
883         }
884         public function insertAfter($baseitem, $item)
885         {
886                 if(!$this->_r)
887                 {
888                         if(($index = $this->indexOf($baseitem)) == -1)
889                                 throw new TInvalidDataValueException('list_item_inexistent');
890                         $this->insertAt($index + 1, $item);
891                         return $index + 1;
892                 }
893                 else
894                         throw new TInvalidOperationException('list_readonly',get_class($this));
895         }
896         public function toArray()
897         {
898                 return $this->_d;
899         }
900         public function copyFrom($data)
901         {
902                 if(is_array($data) || ($data instanceof Traversable))
903                 {
904                         if($this->_c>0)
905                                 $this->clear();
906                         foreach($data as $item)
907                                 $this->add($item);
908                 }
909                 else if($data!==null)
910                         throw new TInvalidDataTypeException('list_data_not_iterable');
911         }
912         public function mergeWith($data)
913         {
914                 if(is_array($data) || ($data instanceof Traversable))
915                 {
916                         foreach($data as $item)
917                                 $this->add($item);
918                 }
919                 else if($data!==null)
920                         throw new TInvalidDataTypeException('list_data_not_iterable');
921         }
922         public function offsetExists($offset)
923         {
924                 return ($offset>=0 && $offset<$this->_c);
925         }
926         public function offsetGet($offset)
927         {
928                 return $this->itemAt($offset);
929         }
930         public function offsetSet($offset,$item)
931         {
932                 if($offset===null || $offset===$this->_c)
933                         $this->insertAt($this->_c,$item);
934                 else
935                 {
936                         $this->removeAt($offset);
937                         $this->insertAt($offset,$item);
938                 }
939         }
940         public function offsetUnset($offset)
941         {
942                 $this->removeAt($offset);
943         }
944 }
945 class TListIterator extends ArrayIterator
946 {
947 }
948 abstract class TCache extends TModule implements ICache, ArrayAccess
949 {
950         private $_prefix=null;
951         private $_primary=true;
952         public function init($config)
953         {
954                 if($this->_prefix===null)
955                         $this->_prefix=$this->getApplication()->getUniqueID();
956                 if($this->_primary)
957                 {
958                         if($this->getApplication()->getCache()===null)
959                                 $this->getApplication()->setCache($this);
960                         else
961                                 throw new TConfigurationException('cache_primary_duplicated',get_class($this));
962                 }
963         }
964         public function getPrimaryCache()
965         {
966                 return $this->_primary;
967         }
968         public function setPrimaryCache($value)
969         {
970                 $this->_primary=TPropertyValue::ensureBoolean($value);
971         }
972         public function getKeyPrefix()
973         {
974                 return $this->_prefix;
975         }
976         public function setKeyPrefix($value)
977         {
978                 $this->_prefix=$value;
979         }
980         protected function generateUniqueKey($key)
981         {
982                 return md5($this->_prefix.$key);
983         }
984         public function get($id)
985         {
986                 if(($data=$this->getValue($this->generateUniqueKey($id)))!==false)
987                 {
988                         if(!is_array($data))
989                                 return false;
990                         if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
991                                 return $data[0];
992                 }
993                 return false;
994         }
995         public function set($id,$value,$expire=0,$dependency=null)
996         {
997                 if(empty($value) && $expire === 0)
998                         $this->delete($id);
999                 else
1000                 {
1001                         $data=array($value,$dependency);
1002                         return $this->setValue($this->generateUniqueKey($id),$data,$expire);
1003                 }
1004         }
1005         public function add($id,$value,$expire=0,$dependency=null)
1006         {
1007                 if(empty($value) && $expire === 0)
1008                         return false;
1009                 $data=array($value,$dependency);
1010                 return $this->addValue($this->generateUniqueKey($id),$data,$expire);
1011         }
1012         public function delete($id)
1013         {
1014                 return $this->deleteValue($this->generateUniqueKey($id));
1015         }
1016         public function flush()
1017         {
1018                 throw new TNotSupportedException('cache_flush_unsupported');
1019         }
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)
1025         {
1026                 return $this->get($id) !== false;
1027         }
1028         public function offsetGet($id)
1029         {
1030                 return $this->get($id);
1031         }
1032         public function offsetSet($id, $value)
1033         {
1034                 $this->set($id, $value);
1035         }
1036         public function offsetUnset($id)
1037         {
1038                 $this->delete($id);
1039         }
1040 }
1041 abstract class TCacheDependency extends TComponent implements ICacheDependency
1042 {
1043 }
1044 class TFileCacheDependency extends TCacheDependency
1045 {
1046         private $_fileName;
1047         private $_timestamp;
1048         public function __construct($fileName)
1049         {
1050                 $this->setFileName($fileName);
1051         }
1052         public function getFileName()
1053         {
1054                 return $this->_fileName;
1055         }
1056         public function setFileName($value)
1057         {
1058                 $this->_fileName=$value;
1059                 $this->_timestamp=@filemtime($value);
1060         }
1061         public function getTimestamp()
1062         {
1063                 return $this->_timestamp;
1064         }
1065         public function getHasChanged()
1066         {
1067                 return @filemtime($this->_fileName)!==$this->_timestamp;
1068         }
1069 }
1070 class TDirectoryCacheDependency extends TCacheDependency
1071 {
1072         private $_recursiveCheck=true;
1073         private $_recursiveLevel=-1;
1074         private $_timestamps;
1075         private $_directory;
1076         public function __construct($directory)
1077         {
1078                 $this->setDirectory($directory);
1079         }
1080         public function getDirectory()
1081         {
1082                 return $this->_directory;
1083         }
1084         public function setDirectory($directory)
1085         {
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);
1090         }
1091         public function getRecursiveCheck()
1092         {
1093                 return $this->_recursiveCheck;
1094         }
1095         public function setRecursiveCheck($value)
1096         {
1097                 $this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
1098         }
1099         public function getRecursiveLevel()
1100         {
1101                 return $this->_recursiveLevel;
1102         }
1103         public function setRecursiveLevel($value)
1104         {
1105                 $this->_recursiveLevel=TPropertyValue::ensureInteger($value);
1106         }
1107         public function getHasChanged()
1108         {
1109                 return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
1110         }
1111         protected function validateFile($fileName)
1112         {
1113                 return true;
1114         }
1115         protected function validateDirectory($directory)
1116         {
1117                 return true;
1118         }
1119         protected function generateTimestamps($directory,$level=0)
1120         {
1121                 if(($dir=opendir($directory))===false)
1122                         throw new TIOException('directorycachedependency_directory_invalid',$directory);
1123                 $timestamps=array();
1124                 while(($file=readdir($dir))!==false)
1125                 {
1126                         $path=$directory.DIRECTORY_SEPARATOR.$file;
1127                         if($file==='.' || $file==='..')
1128                                 continue;
1129                         else if(is_dir($path))
1130                         {
1131                                 if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
1132                                         $timestamps=array_merge($this->generateTimestamps($path,$level+1));
1133                         }
1134                         else if($this->validateFile($path))
1135                                 $timestamps[$path]=filemtime($path);
1136                 }
1137                 closedir($dir);
1138                 return $timestamps;
1139         }
1140 }
1141 class TGlobalStateCacheDependency extends TCacheDependency
1142 {
1143         private $_stateName;
1144         private $_stateValue;
1145         public function __construct($name)
1146         {
1147                 $this->setStateName($name);
1148         }
1149         public function getStateName()
1150         {
1151                 return $this->_stateName;
1152         }
1153         public function setStateName($value)
1154         {
1155                 $this->_stateName=$value;
1156                 $this->_stateValue=Prado::getApplication()->getGlobalState($value);
1157         }
1158         public function getHasChanged()
1159         {
1160                 return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
1161         }
1162 }
1163 class TChainedCacheDependency extends TCacheDependency
1164 {
1165         private $_dependencies=null;
1166         public function getDependencies()
1167         {
1168                 if($this->_dependencies===null)
1169                         $this->_dependencies=new TCacheDependencyList;
1170                 return $this->_dependencies;
1171         }
1172         public function getHasChanged()
1173         {
1174                 if($this->_dependencies!==null)
1175                 {
1176                         foreach($this->_dependencies as $dependency)
1177                                 if($dependency->getHasChanged())
1178                                         return true;
1179                 }
1180                 return false;
1181         }
1182 }
1183 class TApplicationStateCacheDependency extends TCacheDependency
1184 {
1185         public function getHasChanged()
1186         {
1187                 return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
1188         }
1189 }
1190 class TCacheDependencyList extends TList
1191 {
1192         public function insertAt($index,$item)
1193         {
1194                 if($item instanceof ICacheDependency)
1195                         parent::insertAt($index,$item);
1196                 else
1197                         throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
1198         }
1199 }
1200 class TTextWriter extends TComponent implements ITextWriter
1201 {
1202         private $_str='';
1203         public function flush()
1204         {
1205                 $str=$this->_str;
1206                 $this->_str='';
1207                 return $str;
1208         }
1209         public function write($str)
1210         {
1211                 $this->_str.=$str;
1212         }
1213         public function writeLine($str='')
1214         {
1215                 $this->write($str."\n");
1216         }
1217 }
1218 class TPriorityList extends TList
1219 {
1220         private $_d=array();
1221         private $_o=false;
1222         private $_fd=null;
1223         private $_c=0;
1224         private $_dp=10;
1225         private $_p=8;
1226         public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1227         {
1228                 parent::__construct();
1229                 if($data!==null)
1230                         $this->copyFrom($data);
1231                 $this->setReadOnly($readOnly);
1232                 $this->setPrecision($precision);
1233                 $this->setDefaultPriority($defaultPriority);
1234         }
1235         public function count()
1236         {
1237                 return $this->getCount();
1238         }
1239         public function getCount()
1240         {
1241                 return $this->_c;
1242         }
1243         public function getPriorityCount($priority=null)
1244         {
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]))
1249                         return false;
1250                 return count($this->_d[$priority]);
1251         }
1252         public function getDefaultPriority()
1253         {
1254                 return $this->_dp;
1255         }
1256         protected function setDefaultPriority($value)
1257         {
1258                 $this->_dp=(string)round(TPropertyValue::ensureFloat($value),$this->_p);
1259         }
1260         public function getPrecision()
1261         {
1262                 return $this->_p;
1263         }
1264         protected function setPrecision($value)
1265         {
1266                 $this->_p=TPropertyValue::ensureInteger($value);
1267         }
1268         public function getIterator()
1269         {
1270                 return new ArrayIterator($this->flattenPriorities());
1271         }
1272         public function getPriorities()
1273         {
1274                 $this->sortPriorities();
1275                 return array_keys($this->_d);
1276         }
1277         protected function sortPriorities() {
1278                 if(!$this->_o) {
1279                         ksort($this->_d,SORT_NUMERIC);
1280                         $this->_o=true;
1281                 }
1282         }
1283         protected function flattenPriorities() {
1284                 if(is_array($this->_fd))
1285                         return $this->_fd;
1286                 $this->sortPriorities();
1287                 $this->_fd=array();
1288                 foreach($this->_d as $priority => $itemsatpriority)
1289                         $this->_fd=array_merge($this->_fd,$itemsatpriority);
1290                 return $this->_fd;
1291         }
1292         public function itemAt($index)
1293         {
1294                 if($index>=0&&$index<$this->getCount()) {
1295                         $arr=$this->flattenPriorities();
1296                         return $arr[$index];
1297                 } else
1298                         throw new TInvalidDataValueException('list_index_invalid',$index);
1299         }
1300         public function itemsAtPriority($priority=null)
1301         {
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;
1306         }
1307         public function itemAtIndexInPriority($index,$priority=null)
1308         {
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
1314                         );
1315         }
1316         public function add($item,$priority=null)
1317         {
1318                 if($this->getReadOnly())
1319                         throw new TInvalidOperationException('list_readonly',get_class($this));
1320                 return $this->insertAtIndexInPriority($item,false,$priority,true);
1321         }
1322         public function insertAt($index,$item)
1323         {
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]);
1328                 else
1329                         throw new TInvalidDataValueException('list_index_invalid',$index);
1330         }
1331         public function insertAtIndexInPriority($item,$index=false,$priority=null,$preserveCache=false)
1332         {
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();
1340                         $cc=0;
1341                         foreach($this->_d as $prioritykey=>$items)
1342                                 if($prioritykey>=$priority)
1343                                         break;
1344                                 else
1345                                         $cc+=count($items);
1346                         if($index===false&&isset($this->_d[$priority])) {
1347                                 $c=count($this->_d[$priority]);
1348                                 $c+=$cc;
1349                                 $this->_d[$priority][]=$item;
1350                         } else if(isset($this->_d[$priority])) {
1351                                 $c=$index+$cc;
1352                                 array_splice($this->_d[$priority],$index,0,array($item));
1353                         } else {
1354                                 $c = $cc;
1355                                 $this->_o = false;
1356                                 $this->_d[$priority]=array($item);
1357                         }
1358                         if($this->_fd&&is_array($this->_fd))                            array_splice($this->_fd,$c,0,array($item));
1359                 } else {
1360                         $c=null;
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])) {
1365                                 $cc=$index;
1366                                 array_splice($this->_d[$priority],$index,0,array($item));
1367                         } else {
1368                                 $cc=0;
1369                                 $this->_o=false;
1370                                 $this->_d[$priority]=array($item);
1371                         }
1372                         if($this->_fd&&is_array($this->_fd)&&count($this->_d)==1)
1373                                 array_splice($this->_fd,$cc,0,array($item));
1374                         else
1375                                 $this->_fd=null;
1376                 }
1377                 $this->_c++;
1378                 return $c;
1379         }
1380         public function remove($item,$priority=false)
1381         {
1382                 if($this->getReadOnly())
1383                         throw new TInvalidOperationException('list_readonly',get_class($this));
1384                 if(($p=$this->priorityOf($item,true))!==false)
1385                 {
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');
1392                         }
1393                         $this->removeAtIndexInPriority($p[1],$p[0]);
1394                         return $p[2];
1395                 }
1396                 else
1397                         throw new TInvalidDataValueException('list_item_inexistent');
1398         }
1399         public function removeAt($index)
1400         {
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);
1406         }
1407         public function removeAtIndexInPriority($index, $priority=null)
1408         {
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);
1417                 $value=$value[0];
1418                 if(!count($this->_d[$priority]))
1419                         unset($this->_d[$priority]);
1420                 $this->_c--;
1421                 $this->_fd=null;
1422                 return $value;
1423         }
1424         public function clear()
1425         {
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]);
1433                 }
1434         }
1435         public function contains($item)
1436         {
1437                 return $this->indexOf($item)>=0;
1438         }
1439         public function indexOf($item)
1440         {
1441                 if(($index=array_search($item,$this->flattenPriorities(),true))===false)
1442                         return -1;
1443                 else
1444                         return $index;
1445         }
1446         public function priorityOf($item,$withindex = false)
1447         {
1448                 $this->sortPriorities();
1449                 $absindex = 0;
1450                 foreach($this->_d as $priority=>$items) {
1451                         if(($index=array_search($item,$items,true))!==false) {
1452                                 $absindex+=$index;
1453                                 return $withindex?array($priority,$index,$absindex,
1454                                                 'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1455                         } else
1456                                 $absindex+=count($items);
1457                 }
1458                 return false;
1459         }
1460         public function priorityAt($index,$withindex = false)
1461         {
1462                 if($index<0||$index>=$this->getCount())
1463                         throw new TInvalidDataValueException('list_index_invalid',$index);
1464                 $absindex=$index;
1465                 $this->sortPriorities();
1466                 foreach($this->_d as $priority=>$items) {
1467                         if($index>=($c=count($items)))
1468                                 $index-=$c;
1469                         else
1470                                 return $withindex?array($priority,$index,$absindex,
1471                                                 'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1472                 }
1473                 return false;
1474         }
1475         public function insertBefore($indexitem, $item)
1476         {
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];
1483         }
1484         public function insertAfter($indexitem, $item)
1485         {
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;
1492         }
1493         public function toArray()
1494         {
1495                 return $this->flattenPriorities();
1496         }
1497         public function toPriorityArray()
1498         {
1499                 $this->sortPriorities();
1500                 return $this->_d;
1501         }
1502         public function toArrayBelowPriority($priority,$inclusive=false)
1503         {
1504                 $this->sortPriorities();
1505                 $items=array();
1506                 foreach($this->_d as $itemspriority=>$itemsatpriority)
1507                 {
1508                         if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1509                                 break;
1510                         $items=array_merge($items,$itemsatpriority);
1511                 }
1512                 return $items;
1513         }
1514         public function toArrayAbovePriority($priority,$inclusive=true)
1515         {
1516                 $this->sortPriorities();
1517                 $items=array();
1518                 foreach($this->_d as $itemspriority=>$itemsatpriority)
1519                 {
1520                         if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1521                                 continue;
1522                         $items=array_merge($items,$itemsatpriority);
1523                 }
1524                 return $items;
1525         }
1526         public function copyFrom($data)
1527         {
1528                 if($data instanceof TPriorityList)
1529                 {
1530                         if($this->getCount()>0)
1531                                 $this->clear();
1532                         foreach($data->getPriorities() as $priority)
1533                         {
1534                                 foreach($data->itemsAtPriority($priority) as $index=>$item)
1535                                         $this->insertAtIndexInPriority($item,$index,$priority);
1536                         }
1537                 } else if(is_array($data)||$data instanceof Traversable) {
1538                         if($this->getCount()>0)
1539                                 $this->clear();
1540                         foreach($data as $key=>$item)
1541                                 $this->add($item);
1542                 } else if($data!==null)
1543                         throw new TInvalidDataTypeException('map_data_not_iterable');
1544         }
1545         public function mergeWith($data)
1546         {
1547                 if($data instanceof TPriorityList)
1548                 {
1549                         foreach($data->getPriorities() as $priority)
1550                         {
1551                                 foreach($data->itemsAtPriority($priority) as $index=>$item)
1552                                         $this->insertAtIndexInPriority($item,false,$priority);
1553                         }
1554                 }
1555                 else if(is_array($data)||$data instanceof Traversable)
1556                 {
1557                         foreach($data as $priority=>$item)
1558                                 $this->add($item);
1559                 }
1560                 else if($data!==null)
1561                         throw new TInvalidDataTypeException('map_data_not_iterable');
1562         }
1563         public function offsetExists($offset)
1564         {
1565                 return ($offset>=0&&$offset<$this->getCount());
1566         }
1567         public function offsetGet($offset)
1568         {
1569                 return $this->itemAt($offset);
1570         }
1571         public function offsetSet($offset,$item)
1572         {
1573                 if($offset===null)
1574                         return $this->add($item);
1575                 if($offset===$this->getCount()) {
1576                         $priority=$this->priorityAt($offset-1,true);
1577                         $priority[1]++;
1578                 } else {
1579                         $priority=$this->priorityAt($offset,true);
1580                         $this->removeAtIndexInPriority($priority[1],$priority[0]);
1581                 }
1582                 $this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1583         }
1584         public function offsetUnset($offset)
1585         {
1586                 $this->removeAt($offset);
1587         }
1588 }
1589 class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable
1590 {
1591         private $_d=array();
1592         private $_r=false;
1593         protected function _getZappableSleepProps(&$exprops)
1594         {
1595                 parent::_getZappableSleepProps($exprops);
1596                 if ($this->_d===array())
1597                         $exprops[] = "\0TMap\0_d";
1598                 if ($this->_r===false)
1599                         $exprops[] = "\0TMap\0_r";
1600         }
1601         public function __construct($data=null,$readOnly=false)
1602         {
1603                 if($data!==null)
1604                         $this->copyFrom($data);
1605                 $this->setReadOnly($readOnly);
1606         }
1607         public function getReadOnly()
1608         {
1609                 return $this->_r;
1610         }
1611         protected function setReadOnly($value)
1612         {
1613                 $this->_r=TPropertyValue::ensureBoolean($value);
1614         }
1615         public function getIterator()
1616         {
1617                 return new ArrayIterator( $this->_d );
1618         }
1619         public function count()
1620         {
1621                 return $this->getCount();
1622         }
1623         public function getCount()
1624         {
1625                 return count($this->_d);
1626         }
1627         public function getKeys()
1628         {
1629                 return array_keys($this->_d);
1630         }
1631         public function itemAt($key)
1632         {
1633                 return isset($this->_d[$key]) ? $this->_d[$key] : null;
1634         }
1635         public function add($key,$value)
1636         {
1637                 if(!$this->_r)
1638                         $this->_d[$key]=$value;
1639                 else
1640                         throw new TInvalidOperationException('map_readonly',get_class($this));
1641         }
1642         public function remove($key)
1643         {
1644                 if(!$this->_r)
1645                 {
1646                         if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
1647                         {
1648                                 $value=$this->_d[$key];
1649                                 unset($this->_d[$key]);
1650                                 return $value;
1651                         }
1652                         else
1653                                 return null;
1654                 }
1655                 else
1656                         throw new TInvalidOperationException('map_readonly',get_class($this));
1657         }
1658         public function clear()
1659         {
1660                 foreach(array_keys($this->_d) as $key)
1661                         $this->remove($key);
1662         }
1663         public function contains($key)
1664         {
1665                 return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
1666         }
1667         public function toArray()
1668         {
1669                 return $this->_d;
1670         }
1671         public function copyFrom($data)
1672         {
1673                 if(is_array($data) || $data instanceof Traversable)
1674                 {
1675                         if($this->getCount()>0)
1676                                 $this->clear();
1677                         foreach($data as $key=>$value)
1678                                 $this->add($key,$value);
1679                 }
1680                 else if($data!==null)
1681                         throw new TInvalidDataTypeException('map_data_not_iterable');
1682         }
1683         public function mergeWith($data)
1684         {
1685                 if(is_array($data) || $data instanceof Traversable)
1686                 {
1687                         foreach($data as $key=>$value)
1688                                 $this->add($key,$value);
1689                 }
1690                 else if($data!==null)
1691                         throw new TInvalidDataTypeException('map_data_not_iterable');
1692         }
1693         public function offsetExists($offset)
1694         {
1695                 return $this->contains($offset);
1696         }
1697         public function offsetGet($offset)
1698         {
1699                 return $this->itemAt($offset);
1700         }
1701         public function offsetSet($offset,$item)
1702         {
1703                 $this->add($offset,$item);
1704         }
1705         public function offsetUnset($offset)
1706         {
1707                 $this->remove($offset);
1708         }
1709 }
1710 class TMapIterator extends ArrayIterator
1711 {
1712 }
1713 class TPriorityMap extends TMap
1714 {
1715         private $_d=array();
1716         private $_r=false;
1717         private $_o=false;
1718         private $_fd=null;
1719         private $_c=0;
1720         private $_dp=10;
1721         private $_p=8;
1722         public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1723         {
1724                 if($data!==null)
1725                         $this->copyFrom($data);
1726                 $this->setReadOnly($readOnly);
1727                 $this->setPrecision($precision);
1728                 $this->setDefaultPriority($defaultPriority);
1729         }
1730         public function getReadOnly()
1731         {
1732                 return $this->_r;
1733         }
1734         protected function setReadOnly($value)
1735         {
1736                 $this->_r=TPropertyValue::ensureBoolean($value);
1737         }
1738         public function getDefaultPriority()
1739         {
1740                 return $this->_dp;
1741         }
1742         protected function setDefaultPriority($value)
1743         {
1744                 $this->_dp = (string)round(TPropertyValue::ensureFloat($value), $this->_p);
1745         }
1746         public function getPrecision()
1747         {
1748                 return $this->_p;
1749         }
1750         protected function setPrecision($value)
1751         {
1752                 $this->_p=TPropertyValue::ensureInteger($value);
1753         }
1754         public function getIterator()
1755         {
1756                 return new ArrayIterator($this->flattenPriorities());
1757         }
1758         protected function sortPriorities() {
1759                 if(!$this->_o) {
1760                         ksort($this->_d, SORT_NUMERIC);
1761                         $this->_o=true;
1762                 }
1763         }
1764         protected function flattenPriorities() {
1765                 if(is_array($this->_fd))
1766                         return $this->_fd;
1767                 $this->sortPriorities();
1768                 $this->_fd = array();
1769                 foreach($this->_d as $priority => $itemsatpriority)
1770                         $this->_fd = array_merge($this->_fd, $itemsatpriority);
1771                 return $this->_fd;
1772         }
1773         public function count()
1774         {
1775                 return $this->getCount();
1776         }
1777         public function getCount()
1778         {
1779                 return $this->_c;
1780         }
1781         public function getPriorityCount($priority=null)
1782         {
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]))
1787                         return false;
1788                 return count($this->_d[$priority]);
1789         }
1790         public function getPriorities()
1791         {
1792                 $this->sortPriorities();
1793                 return array_keys($this->_d);
1794         }
1795         public function getKeys()
1796         {
1797                 return array_keys($this->flattenPriorities());
1798         }
1799         public function itemAt($key,$priority=false)
1800         {
1801                 if($priority===false){
1802                         $map=$this->flattenPriorities();
1803                         return isset($map[$key])?$map[$key]:null;
1804                 } else {
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;
1809                 }
1810         }
1811         public function setPriorityAt($key,$priority=null)
1812         {
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);
1820                 }
1821                 return $oldpriority;
1822         }
1823         public function itemsAtPriority($priority=null)
1824         {
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;
1829         }
1830         public function priorityOf($item)
1831         {
1832                 $this->sortPriorities();
1833                 foreach($this->_d as $priority=>$items)
1834                         if(($index=array_search($item,$items,true))!==false)
1835                                 return $priority;
1836                 return false;
1837         }
1838         public function priorityAt($key)
1839         {
1840                 $this->sortPriorities();
1841                 foreach($this->_d as $priority=>$items)
1842                         if(array_key_exists($key,$items))
1843                                 return $priority;
1844                 return false;
1845         }
1846         public function add($key,$value,$priority=null)
1847         {
1848                 if($priority===null)
1849                         $priority=$this->getDefaultPriority();
1850                 $priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1851                 if(!$this->_r)
1852                 {
1853                         foreach($this->_d as $innerpriority=>$items)
1854                                 if(array_key_exists($key,$items))
1855                                 {
1856                                         unset($this->_d[$innerpriority][$key]);
1857                                         $this->_c--;
1858                                         if(count($this->_d[$innerpriority])===0)
1859                                                 unset($this->_d[$innerpriority]);
1860                                 }
1861                         if(!isset($this->_d[$priority])) {
1862                                 $this->_d[$priority]=array($key=>$value);
1863                                 $this->_o=false;
1864                         }
1865                         else
1866                                 $this->_d[$priority][$key]=$value;
1867                         $this->_c++;
1868                         $this->_fd=null;
1869                 }
1870                 else
1871                         throw new TInvalidOperationException('map_readonly',get_class($this));
1872                 return $priority;
1873         }
1874         public function remove($key,$priority=false)
1875         {
1876                 if(!$this->_r)
1877                 {
1878                         if($priority===null)
1879                                 $priority=$this->getDefaultPriority();
1880                         if($priority===false)
1881                         {
1882                                 $this->sortPriorities();
1883                                 foreach($this->_d as $priority=>$items)
1884                                         if(array_key_exists($key,$items))
1885                                         {
1886                                                 $value=$this->_d[$priority][$key];
1887                                                 unset($this->_d[$priority][$key]);
1888                                                 $this->_c--;
1889                                                 if(count($this->_d[$priority])===0)
1890                                                 {
1891                                                         unset($this->_d[$priority]);
1892                                                         $this->_o=false;
1893                                                 }
1894                                                 $this->_fd=null;
1895                                                 return $value;
1896                                         }
1897                                 return null;
1898                         }
1899                         else
1900                         {
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])))
1903                                 {
1904                                         $value=$this->_d[$priority][$key];
1905                                         unset($this->_d[$priority][$key]);
1906                                         $this->_c--;
1907                                         if(count($this->_d[$priority])===0) {
1908                                                 unset($this->_d[$priority]);
1909                                                 $this->_o=false;
1910                                         }
1911                                         $this->_fd=null;
1912                                         return $value;
1913                                 }
1914                                 else
1915                                         return null;
1916                         }
1917                 }
1918                 else
1919                         throw new TInvalidOperationException('map_readonly',get_class($this));
1920         }
1921         public function clear()
1922         {
1923                 foreach($this->_d as $priority=>$items)
1924                         foreach(array_keys($items) as $key)
1925                                 $this->remove($key);
1926         }
1927         public function contains($key)
1928         {
1929                 $map=$this->flattenPriorities();
1930                 return isset($map[$key])||array_key_exists($key,$map);
1931         }
1932         public function toArray()
1933         {
1934                 return $this->flattenPriorities();
1935         }
1936         public function toArrayBelowPriority($priority,$inclusive=false)
1937         {
1938                 $this->sortPriorities();
1939                 $items=array();
1940                 foreach($this->_d as $itemspriority=>$itemsatpriority)
1941                 {
1942                         if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1943                                 break;
1944                         $items=array_merge($items,$itemsatpriority);
1945                 }
1946                 return $items;
1947         }
1948         public function toArrayAbovePriority($priority,$inclusive=true)
1949         {
1950                 $this->sortPriorities();
1951                 $items=array();
1952                 foreach($this->_d as $itemspriority=>$itemsatpriority)
1953                 {
1954                         if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1955                                 continue;
1956                         $items=array_merge($items,$itemsatpriority);
1957                 }
1958                 return $items;
1959         }
1960         public function copyFrom($data)
1961         {
1962                 if($data instanceof TPriorityMap)
1963                 {
1964                         if($this->getCount()>0)
1965                                 $this->clear();
1966                         foreach($data->getPriorities() as $priority) {
1967                                 foreach($data->itemsAtPriority($priority) as $key => $value) {
1968                                         $this->add($key,$value,$priority);
1969                                 }
1970                         }
1971                 }
1972                 else if(is_array($data)||$data instanceof Traversable)
1973                 {
1974                         if($this->getCount()>0)
1975                                 $this->clear();
1976                         foreach($data as $key=>$value)
1977                                 $this->add($key,$value);
1978                 }
1979                 else if($data!==null)
1980                         throw new TInvalidDataTypeException('map_data_not_iterable');
1981         }
1982         public function mergeWith($data)
1983         {
1984                 if($data instanceof TPriorityMap)
1985                 {
1986                         foreach($data->getPriorities() as $priority)
1987                         {
1988                                 foreach($data->itemsAtPriority($priority) as $key => $value)
1989                                         $this->add($key,$value,$priority);
1990                         }
1991                 }
1992                 else if(is_array($data)||$data instanceof Traversable)
1993                 {
1994                         foreach($data as $key=>$value)
1995                                 $this->add($key,$value);
1996                 }
1997                 else if($data!==null)
1998                         throw new TInvalidDataTypeException('map_data_not_iterable');
1999         }
2000         public function offsetExists($offset)
2001         {
2002                 return $this->contains($offset);
2003         }
2004         public function offsetGet($offset)
2005         {
2006                 return $this->itemAt($offset);
2007         }
2008         public function offsetSet($offset,$item)
2009         {
2010                 $this->add($offset,$item);
2011         }
2012         public function offsetUnset($offset)
2013         {
2014                 $this->remove($offset);
2015         }
2016 }
2017 class TStack extends TComponent implements IteratorAggregate,Countable
2018 {
2019         private $_d=array();
2020         private $_c=0;
2021         public function __construct($data=null)
2022         {
2023                 if($data!==null)
2024                         $this->copyFrom($data);
2025         }
2026         public function toArray()
2027         {
2028                 return $this->_d;
2029         }
2030         public function copyFrom($data)
2031         {
2032                 if(is_array($data) || ($data instanceof Traversable))
2033                 {
2034                         $this->clear();
2035                         foreach($data as $item)
2036                         {
2037                                 $this->_d[]=$item;
2038                                 ++$this->_c;
2039                         }
2040                 }
2041                 else if($data!==null)
2042                         throw new TInvalidDataTypeException('stack_data_not_iterable');
2043         }
2044         public function clear()
2045         {
2046                 $this->_c=0;
2047                 $this->_d=array();
2048         }
2049         public function contains($item)
2050         {
2051                 return array_search($item,$this->_d,true)!==false;
2052         }
2053         public function peek()
2054         {
2055                 if($this->_c===0)
2056                         throw new TInvalidOperationException('stack_empty');
2057                 else
2058                         return $this->_d[$this->_c-1];
2059         }
2060         public function pop()
2061         {
2062                 if($this->_c===0)
2063                         throw new TInvalidOperationException('stack_empty');
2064                 else
2065                 {
2066                         --$this->_c;
2067                         return array_pop($this->_d);
2068                 }
2069         }
2070         public function push($item)
2071         {
2072                 ++$this->_c;
2073                 $this->_d[] = $item;
2074         }
2075         public function getIterator()
2076         {
2077                 return new ArrayIterator( $this->_d );
2078         }
2079         public function getCount()
2080         {
2081                 return $this->_c;
2082         }
2083         public function count()
2084         {
2085                 return $this->getCount();
2086         }
2087 }
2088 class TStackIterator implements Iterator
2089 {
2090         private $_d;
2091         private $_i;
2092         private $_c;
2093         public function __construct(&$data)
2094         {
2095                 $this->_d=&$data;
2096                 $this->_i=0;
2097                 $this->_c=count($this->_d);
2098         }
2099         public function rewind()
2100         {
2101                 $this->_i=0;
2102         }
2103         public function key()
2104         {
2105                 return $this->_i;
2106         }
2107         public function current()
2108         {
2109                 return $this->_d[$this->_i];
2110         }
2111         public function next()
2112         {
2113                 $this->_i++;
2114         }
2115         public function valid()
2116         {
2117                 return $this->_i<$this->_c;
2118         }
2119 }
2120 class TXmlElement extends TComponent
2121 {
2122         private $_parent=null;
2123         private $_tagName='unknown';
2124         private $_value='';
2125         private $_elements=null;
2126         private $_attributes=null;
2127         public function __construct($tagName)
2128         {
2129                 $this->setTagName($tagName);
2130         }
2131         public function getParent()
2132         {
2133                 return $this->_parent;
2134         }
2135         public function setParent($parent)
2136         {
2137                 $this->_parent=$parent;
2138         }
2139         public function getTagName()
2140         {
2141                 return $this->_tagName;
2142         }
2143         public function setTagName($tagName)
2144         {
2145                 $this->_tagName=$tagName;
2146         }
2147         public function getValue()
2148         {
2149                 return $this->_value;
2150         }
2151         public function setValue($value)
2152         {
2153                 $this->_value=TPropertyValue::ensureString($value);
2154         }
2155         public function getHasElement()
2156         {
2157                 return $this->_elements!==null && $this->_elements->getCount()>0;
2158         }
2159         public function getHasAttribute()
2160         {
2161                 return $this->_attributes!==null && $this->_attributes->getCount()>0;
2162         }
2163         public function getAttribute($name)
2164         {
2165                 if($this->_attributes!==null)
2166                         return $this->_attributes->itemAt($name);
2167                 else
2168                         return null;
2169         }
2170         public function setAttribute($name,$value)
2171         {
2172                 $this->getAttributes()->add($name,TPropertyValue::ensureString($value));
2173         }
2174         public function getElements()
2175         {
2176                 if(!$this->_elements)
2177                         $this->_elements=new TXmlElementList($this);
2178                 return $this->_elements;
2179         }
2180         public function getAttributes()
2181         {
2182                 if(!$this->_attributes)
2183                         $this->_attributes=new TMap;
2184                 return $this->_attributes;
2185         }
2186         public function getElementByTagName($tagName)
2187         {
2188                 if($this->_elements)
2189                 {
2190                         foreach($this->_elements as $element)
2191                                 if($element->_tagName===$tagName)
2192                                         return $element;
2193                 }
2194                 return null;
2195         }
2196         public function getElementsByTagName($tagName)
2197         {
2198                 $list=new TList;
2199                 if($this->_elements)
2200                 {
2201                         foreach($this->_elements as $element)
2202                                 if($element->_tagName===$tagName)
2203                                         $list->add($element);
2204                 }
2205                 return $list;
2206         }
2207         public function toString($indent=0)
2208         {
2209                 $attr='';
2210                 if($this->_attributes!==null)
2211                 {
2212                         foreach($this->_attributes as $name=>$value)
2213                         {
2214                                 $value=$this->xmlEncode($value);
2215                                 $attr.=" $name=\"$value\"";
2216                         }
2217                 }
2218                 $prefix=str_repeat(' ',$indent*4);
2219                 if($this->getHasElement())
2220                 {
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}>";
2225                         return $str;
2226                 }
2227                 else if(($value=$this->getValue())!=='')
2228                 {
2229                         $value=$this->xmlEncode($value);
2230                         return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>";
2231                 }
2232                 else
2233                         return $prefix."<{$this->_tagName}$attr />";
2234         }
2235         public function __toString()
2236         {
2237                 return $this->toString();
2238         }
2239         private function xmlEncode($str)
2240         {
2241                 return strtr($str,array(
2242                         '>'=>'&gt;',
2243                         '<'=>'&lt;',
2244                         '&'=>'&amp;',
2245                         '"'=>'&quot;',
2246                         "\r"=>'&#xD;',
2247                         "\t"=>'&#x9;',
2248                         "\n"=>'&#xA;'));
2249         }
2250 }
2251 class TXmlDocument extends TXmlElement
2252 {
2253         private $_version;
2254         private $_encoding;
2255         public function __construct($version='1.0',$encoding='')
2256         {
2257                 parent::__construct('');
2258                 $this->setVersion($version);
2259                 $this->setEncoding($encoding);
2260         }
2261         public function getVersion()
2262         {
2263                 return $this->_version;
2264         }
2265         public function setVersion($version)
2266         {
2267                 $this->_version=$version;
2268         }
2269         public function getEncoding()
2270         {
2271                 return $this->_encoding;
2272         }
2273         public function setEncoding($encoding)
2274         {
2275                 $this->_encoding=$encoding;
2276         }
2277         public function loadFromFile($file)
2278         {
2279                 if(($str=@file_get_contents($file))!==false)
2280                         return $this->loadFromString($str);
2281                 else
2282                         throw new TIOException('xmldocument_file_read_failed',$file);
2283         }
2284         public function loadFromString($string)
2285         {
2286                                 $doc=new DOMDocument();
2287                 if($doc->loadXML($string)===false)
2288                         return 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();
2296                 $elements->clear();
2297                 $attributes->clear();
2298                 static $bSimpleXml;
2299                 if($bSimpleXml === null)
2300                         $bSimpleXml = (boolean)function_exists('simplexml_load_string');
2301                 if($bSimpleXml)
2302                 {
2303                         $simpleDoc = simplexml_load_string($string);
2304                         $docNamespaces = $simpleDoc->getDocNamespaces(false);
2305                         $simpleDoc = null;
2306                         foreach($docNamespaces as $prefix => $uri)
2307                         {
2308                                 if($prefix === '')
2309                                         $attributes->add('xmlns', $uri);
2310                                 else
2311                                         $attributes->add('xmlns:'.$prefix, $uri);
2312                         }
2313                 }
2314                 foreach($element->attributes as $name=>$attr)
2315                         $attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value);
2316                 foreach($element->childNodes as $child)
2317                 {
2318                         if($child instanceof DOMElement)
2319                                 $elements->add($this->buildElement($child));
2320                 }
2321                 return true;
2322         }
2323         public function saveToFile($file)
2324         {
2325                 if(($fw=fopen($file,'w'))!==false)
2326                 {
2327                         fwrite($fw,$this->saveToString());
2328                         fclose($fw);
2329                 }
2330                 else
2331                         throw new TIOException('xmldocument_file_write_failed',$file);
2332         }
2333         public function saveToString()
2334         {
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);
2338         }
2339         public function __toString()
2340         {
2341                 return $this->saveToString();
2342         }
2343         protected function buildElement($node)
2344         {
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)
2350                 {
2351                         if($child instanceof DOMElement)
2352                                 $element->getElements()->add($this->buildElement($child));
2353                 }
2354                 return $element;
2355         }
2356 }
2357 class TXmlElementList extends TList
2358 {
2359         private $_o;
2360         public function __construct(TXmlElement $owner)
2361         {
2362                 $this->_o=$owner;
2363         }
2364         protected function getOwner()
2365         {
2366                 return $this->_o;
2367         }
2368         public function insertAt($index,$item)
2369         {
2370                 if($item instanceof TXmlElement)
2371                 {
2372                         parent::insertAt($index,$item);
2373                         if($item->getParent()!==null)
2374                                 $item->getParent()->getElements()->remove($item);
2375                         $item->setParent($this->_o);
2376                 }
2377                 else
2378                         throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
2379         }
2380         public function removeAt($index)
2381         {
2382                 $item=parent::removeAt($index);
2383                 if($item instanceof TXmlElement)
2384                         $item->setParent(null);
2385                 return $item;
2386         }
2387 }
2388 class TAuthorizationRule extends TComponent
2389 {
2390         private $_action;
2391         private $_users;
2392         private $_roles;
2393         private $_verb;
2394         private $_ipRules;
2395         private $_everyone;
2396         private $_guest;
2397         private $_authenticated;
2398         public function __construct($action,$users,$roles,$verb='',$ipRules='')
2399         {
2400                 $action=strtolower(trim($action));
2401                 if($action==='allow' || $action==='deny')
2402                         $this->_action=$action;
2403                 else
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)==='')
2412                         $users='*';
2413                 foreach(explode(',',$users) as $user)
2414                 {
2415                         if(($user=trim(strtolower($user)))!=='')
2416                         {
2417                                 if($user==='*')
2418                                 {
2419                                         $this->_everyone=true;
2420                                         break;
2421                                 }
2422                                 else if($user==='?')
2423                                         $this->_guest=true;
2424                                 else if($user==='@')
2425                                         $this->_authenticated=true;
2426                                 else
2427                                         $this->_users[]=$user;
2428                         }
2429                 }
2430                 if(trim($roles)==='')
2431                         $roles='*';
2432                 foreach(explode(',',$roles) as $role)
2433                 {
2434                         if(($role=trim(strtolower($role)))!=='')
2435                                 $this->_roles[]=$role;
2436                 }
2437                 if(($verb=trim(strtolower($verb)))==='')
2438                         $verb='*';
2439                 if($verb==='*' || $verb==='get' || $verb==='post')
2440                         $this->_verb=$verb;
2441                 else
2442                         throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb);
2443                 if(trim($ipRules)==='')
2444                         $ipRules='*';
2445                 foreach(explode(',',$ipRules) as $ipRule)
2446                 {
2447                         if(($ipRule=trim($ipRule))!=='')
2448                                 $this->_ipRules[]=$ipRule;
2449                 }
2450         }
2451         public function getAction()
2452         {
2453                 return $this->_action;
2454         }
2455         public function getUsers()
2456         {
2457                 return $this->_users;
2458         }
2459         public function getRoles()
2460         {
2461                 return $this->_roles;
2462         }
2463         public function getVerb()
2464         {
2465                 return $this->_verb;
2466         }
2467         public function getIPRules()
2468         {
2469                 return $this->_ipRules;
2470         }
2471         public function getGuestApplied()
2472         {
2473                 return $this->_guest || $this->_everyone;
2474         }
2475         public function getEveryoneApplied()
2476         {
2477                 return $this->_everyone;
2478         }
2479         public function getAuthenticatedApplied()
2480         {
2481                 return $this->_authenticated || $this->_everyone;
2482         }
2483         public function isUserAllowed(IUser $user,$verb,$ip)
2484         {
2485                 if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user))
2486                         return ($this->_action==='allow')?1:-1;
2487                 else
2488                         return 0;
2489         }
2490         private function isIpMatched($ip)
2491         {
2492                 if(empty($this->_ipRules))
2493                         return 1;
2494                 foreach($this->_ipRules as $rule)
2495                 {
2496                         if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0))
2497                                 return 1;
2498                 }
2499                 return 0;
2500         }
2501         private function isUserMatched($user)
2502         {
2503                 return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users));
2504         }
2505         private function isRoleMatched($user)
2506         {
2507                 foreach($this->_roles as $role)
2508                 {
2509                         if($role==='*' || $user->isInRole($role))
2510                                 return true;
2511                 }
2512                 return false;
2513         }
2514         private function isVerbMatched($verb)
2515         {
2516                 return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0);
2517         }
2518 }
2519 class TAuthorizationRuleCollection extends TList
2520 {
2521         public function isUserAllowed($user,$verb,$ip)
2522         {
2523                 if($user instanceof IUser)
2524                 {
2525                         $verb=strtolower(trim($verb));
2526                         foreach($this as $rule)
2527                         {
2528                                 if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0)
2529                                         return ($decision>0);
2530                         }
2531                         return true;
2532                 }
2533                 else
2534                         return false;
2535         }
2536         public function insertAt($index,$item)
2537         {
2538                 if($item instanceof TAuthorizationRule)
2539                         parent::insertAt($index,$item);
2540                 else
2541                         throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required');
2542         }
2543 }
2544 class TSecurityManager extends TModule
2545 {
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';
2552         private $_mbstring;
2553         public function init($config)
2554         {
2555                 $this->_mbstring=extension_loaded('mbstring');
2556                 $this->getApplication()->setSecurityManager($this);
2557         }
2558         protected function generateRandomKey()
2559         {
2560                 return sprintf('%08x%08x%08x%08x',mt_rand(),mt_rand(),mt_rand(),mt_rand());
2561         }
2562         public function getValidationKey()
2563         {
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);
2568                         }
2569                 }
2570                 return $this->_validationKey;
2571         }
2572         public function setValidationKey($value)
2573         {
2574                 if('' === $value)
2575                         throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
2576                 $this->_validationKey = $value;
2577         }
2578         public function getEncryptionKey()
2579         {
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);
2584                         }
2585                 }
2586                 return $this->_encryptionKey;
2587         }
2588         public function setEncryptionKey($value)
2589         {
2590                 if('' === $value)
2591                         throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
2592                 $this->_encryptionKey = $value;
2593         }
2594         public function getValidation()
2595         {
2596                 return $this->_hashAlgorithm;
2597         }
2598         public function getHashAlgorithm()
2599         {
2600                 return $this->_hashAlgorithm;
2601         }
2602         public function setValidation($value)
2603         {
2604                 $this->_hashAlgorithm = TPropertyValue::ensureEnum($value, 'TSecurityManagerValidationMode');
2605         }
2606         public function setHashAlgorithm($value)
2607         {
2608                 $this->_hashAlgorithm = TPropertyValue::ensureString($value);
2609         }
2610         public function getEncryption()
2611         {
2612                 if(is_string($this->_cryptAlgorithm))
2613                         return $this->_cryptAlgorithm;
2614                                 return "3DES";
2615         }
2616         public function setEncryption($value)
2617         {
2618                 $this->_cryptAlgorithm = $value;
2619         }
2620         public function getCryptAlgorithm()
2621         {
2622                 return $this->_cryptAlgorithm;
2623         }
2624         public function setCryptAlgorithm($value)
2625         {
2626                 $this->_cryptAlgorithm = $value;
2627         }
2628         public function encrypt($data)
2629         {
2630                 $module=$this->openCryptModule();
2631                 $key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
2632                 srand();
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);
2638                 return $encrypted;
2639         }
2640         public function decrypt($data)
2641         {
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);
2650                 return $decrypted;
2651         }
2652         protected function openCryptModule()
2653         {
2654                 if(extension_loaded('mcrypt'))
2655                 {
2656                         if(is_array($this->_cryptAlgorithm))
2657                                 $module=@call_user_func_array('mcrypt_module_open',$this->_cryptAlgorithm);
2658                         else
2659                                 $module=@mcrypt_module_open($this->_cryptAlgorithm,'', MCRYPT_MODE_CBC,'');
2660                         if($module===false)
2661                                 throw new TNotSupportedException('securitymanager_mcryptextension_initfailed');
2662                         return $module;
2663                 }
2664                 else
2665                         throw new TNotSupportedException('securitymanager_mcryptextension_required');
2666         }
2667         public function hashData($data)
2668         {
2669                 $hmac = $this->computeHMAC($data);
2670                 return $hmac.$data;
2671         }
2672         public function validateData($data)
2673         {
2674                 $len=$this->strlen($this->computeHMAC('test'));
2675                 if($this->strlen($data) < $len)
2676                         return false;
2677                 $hmac = $this->substr($data, 0, $len);
2678                 $data2=$this->substr($data, $len, $this->strlen($data));
2679                 return $hmac === $this->computeHMAC($data2) ? $data2 : false;
2680         }
2681         protected function computeHMAC($data)
2682         {
2683                 $key = $this->getValidationKey();
2684                 if(function_exists('hash_hmac'))
2685                         return hash_hmac($this->_hashAlgorithm, $data, $key);
2686                 if(!strcasecmp($this->_hashAlgorithm,'sha1'))
2687                 {
2688                         $pack = 'H40';
2689                         $func = 'sha1';
2690                 } else {
2691                         $pack = 'H32';
2692                         $func = 'md5';
2693                 }
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)));
2696         }
2697         private function strlen($string)
2698         {
2699                 return $this->_mbstring ? mb_strlen($string,'8bit') : strlen($string);
2700         }
2701         private function substr($string,$start,$length)
2702         {
2703                 return $this->_mbstring ? mb_substr($string,$start,$length,'8bit') : substr($string,$start,$length);
2704         }
2705 }
2706 class TSecurityManagerValidationMode extends TEnumerable
2707 {
2708         const MD5 = 'MD5';
2709         const SHA1 = 'SHA1';
2710 }
2711 class THttpUtility
2712 {
2713         private static $_encodeTable=array('<'=>'&lt;','>'=>'&gt;','"'=>'&quot;');
2714         private static $_decodeTable=array('&lt;'=>'<','&gt;'=>'>','&quot;'=>'"');
2715         private static $_stripTable=array('&lt;'=>'','&gt;'=>'','&quot;'=>'');
2716         public static function htmlEncode($s)
2717         {
2718                 return strtr($s,self::$_encodeTable);
2719         }
2720         public static function htmlDecode($s)
2721         {
2722                 return strtr($s,self::$_decodeTable);
2723         }
2724         public static function htmlStrip($s)
2725         {
2726                 return strtr($s,self::$_stripTable);
2727         }
2728 }
2729 class TJavaScript
2730 {
2731         public static function renderScriptFiles($files)
2732         {
2733                 $str='';
2734                 foreach($files as $file)
2735                         $str.= self::renderScriptFile($file);
2736                 return $str;
2737         }
2738         public static function renderScriptFile($file)
2739         {
2740                 return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
2741         }
2742         public static function renderScriptBlocks($scripts)
2743         {
2744                 if(count($scripts))
2745                         return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
2746                 else
2747                         return '';
2748         }
2749         public static function renderScriptBlocksCallback($scripts)
2750         {
2751                 if(count($scripts))
2752                         return implode("\n",$scripts)."\n";
2753                 else
2754                         return '';
2755         }
2756         public static function renderScriptBlock($script)
2757         {
2758                 return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
2759         }
2760         public static function quoteString($js)
2761         {
2762                 return self::jsonEncode($js,JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG);
2763         }
2764         public static function quoteJsLiteral($js)
2765         {
2766                 if($js instanceof TJavaScriptLiteral)
2767                         return $js;
2768                 else
2769                         return new TJavaScriptLiteral($js);
2770         }
2771         public static function quoteFunction($js)
2772         {
2773                 return self::quoteJsLiteral($js);
2774         }
2775         public static function isJsLiteral($js)
2776         {
2777                 return ($js instanceof TJavaScriptLiteral);
2778         }
2779         public static function isFunction($js)
2780         {
2781                 return self::isJsLiteral($js);
2782         }
2783         public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
2784         {
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))
2790                 {
2791                         $results='';
2792                         if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
2793                         {
2794                                 foreach($value as $k=>$v)
2795                                 {
2796                                         if($v!=='' || $encodeEmptyStrings)
2797                                         {
2798                                                 if($results!=='')
2799                                                         $results.=',';
2800                                                 $results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings);
2801                                         }
2802                                 }
2803                                 return '{'.$results.'}';
2804                         }
2805                         else
2806                         {
2807                                 foreach($value as $v)
2808                                 {
2809                                         if($v!=='' || $encodeEmptyStrings)
2810                                         {
2811                                                 if($results!=='')
2812                                                         $results.=',';
2813                                                 $results.=self::encode($v,$toMap, $encodeEmptyStrings);
2814                                         }
2815                                 }
2816                                 return '['.$results.']';
2817                         }
2818                 }
2819                 else if(is_integer($value))
2820                         return "$value";
2821                 else if(is_float($value))
2822                 {
2823                         switch($value)
2824                         {
2825                                 case -INF:
2826                                         return 'Number.NEGATIVE_INFINITY';
2827                                         break;
2828                                 case INF:
2829                                         return 'Number.POSITIVE_INFINITY';
2830                                         break;
2831                                 default:
2832                                         $locale=localeConv();
2833                                         if($locale['decimal_point']=='.')
2834                                                 return "$value";
2835                                         else
2836                                                 return str_replace($locale['decimal_point'], '.', "$value");
2837                                         break;
2838                         }
2839                 }
2840                 else if(is_object($value))
2841                         if ($value instanceof TJavaScriptLiteral)
2842                                 return $value->toJavaScriptLiteral();
2843                         else
2844                                 return self::encode(get_object_vars($value),$toMap);
2845                 else if($value===null)
2846                         return 'null';
2847                 else
2848                         return '';
2849         }
2850         public static function jsonEncode($value, $options = 0)
2851         {
2852                 if (($g=Prado::getApplication()->getGlobalization(false))!==null &&
2853                         strtoupper($enc=$g->getCharset())!='UTF-8') {
2854                         self::convertToUtf8($value, $enc);
2855                 }
2856                 $s = @json_encode($value,$options);
2857                 self::checkJsonError();
2858                 return $s;
2859         }
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))
2864                 {
2865                         foreach($value as &$element)
2866                                 self::convertToUtf8($element, $sourceEncoding);
2867                 }
2868         }
2869         public static function jsonDecode($value, $assoc = false, $depth = 512)
2870         {
2871                 $s= @json_decode($value, $assoc, $depth);
2872                 self::checkJsonError();
2873                 return $s;
2874         }
2875         private static function checkJsonError()
2876         {
2877                 switch ($err = json_last_error())
2878                 {
2879                         case JSON_ERROR_NONE:
2880                                 return;
2881                                 break;
2882                         case JSON_ERROR_DEPTH:
2883                                 $msg = 'Maximum stack depth exceeded';
2884                                 break;
2885                         case JSON_ERROR_STATE_MISMATCH:
2886                                 $msg = 'Underflow or the modes mismatch';
2887                                 break;
2888                         case JSON_ERROR_CTRL_CHAR:
2889                                 $msg = 'Unexpected control character found';
2890                                 break;
2891                         case JSON_ERROR_SYNTAX:
2892                                 $msg = 'Syntax error, malformed JSON';
2893                                 break;
2894                         case JSON_ERROR_UTF8:
2895                                 $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
2896                                 break;
2897                         default:
2898                                 $msg = 'Unknown error';
2899                                 break;
2900                 }
2901                 throw new Exception("JSON error ($err): $msg");
2902         }
2903         public static function JSMin($code)
2904         {
2905                 Prado::using('System.Web.Javascripts.JSMin');
2906                 return JSMin::minify($code);
2907         }
2908 }
2909 class TUrlManager extends TModule
2910 {
2911         public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
2912         {
2913                 $url=$serviceID.'='.urlencode($serviceParam);
2914                 $amp=$encodeAmpersand?'&amp;':'&';
2915                 $request=$this->getRequest();
2916                 if(is_array($getItems) || $getItems instanceof Traversable)
2917                 {
2918                         if($encodeGetItems)
2919                         {
2920                                 foreach($getItems as $name=>$value)
2921                                 {
2922                                         if(is_array($value))
2923                                         {
2924                                                 $name=urlencode($name.'[]');
2925                                                 foreach($value as $v)
2926                                                         $url.=$amp.$name.'='.urlencode($v);
2927                                         }
2928                                         else
2929                                                 $url.=$amp.urlencode($name).'='.urlencode($value);
2930                                 }
2931                         }
2932                         else
2933                         {
2934                                 foreach($getItems as $name=>$value)
2935                                 {
2936                                         if(is_array($value))
2937                                         {
2938                                                 foreach($value as $v)
2939                                                         $url.=$amp.$name.'[]='.$v;
2940                                         }
2941                                         else
2942                                                 $url.=$amp.$name.'='.$value;
2943                                 }
2944                         }
2945                 }
2946                 switch($request->getUrlFormat())
2947                 {
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()));
2952                         default:
2953                                 return $request->getApplicationUrl().'?'.$url;
2954                 }
2955         }
2956         public function parseUrl()
2957         {
2958                 $request=$this->getRequest();
2959                 $pathInfo=trim($request->getPathInfo(),'/');
2960                 if(($request->getUrlFormat()===THttpRequestUrlFormat::Path ||
2961                         $request->getUrlFormat()===THttpRequestUrlFormat::HiddenPath) &&
2962                         $pathInfo!=='')
2963                 {
2964                         $separator=$request->getUrlParamSeparator();
2965                         $paths=explode('/',$pathInfo);
2966                         $getVariables=array();
2967                         foreach($paths as $path)
2968                         {
2969                                 if(($path=trim($path))!=='')
2970                                 {
2971                                         if(($pos=strpos($path,$separator))!==false)
2972                                         {
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;
2977                                                 else
2978                                                         $getVariables[$name]=$value;
2979                                         }
2980                                         else
2981                                                 $getVariables[$path]='';
2982                                 }
2983                         }
2984                         return $getVariables;
2985                 }
2986                 else
2987                         return array();
2988         }
2989 }
2990 class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
2991 {
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;
3001         private $_pathInfo;
3002         private $_cookieOnly=null;
3003         private $_urlFormat=THttpRequestUrlFormat::Get;
3004         private $_services;
3005         private $_requestResolved=false;
3006         private $_enableCookieValidation=false;
3007         private $_cgiFix=0;
3008         private $_enableCache=false;
3009         private $_url=null;
3010         private $_id;
3011         private $_items=array();
3012         public function getID()
3013         {
3014                 return $this->_id;
3015         }
3016         public function setID($value)
3017         {
3018                 $this->_id=$value;
3019         }
3020         public function init($config)
3021         {
3022                                 if(php_sapi_name()==='cli')
3023                 {
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']='';
3029                 }
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']));
3039                 else
3040                         $this->_pathInfo='';
3041                 if(get_magic_quotes_gpc())
3042                 {
3043                         if(isset($_GET))
3044                                 $_GET=$this->stripSlashes($_GET);
3045                         if(isset($_POST))
3046                                 $_POST=$this->stripSlashes($_POST);
3047                         if(isset($_REQUEST))
3048                                 $_REQUEST=$this->stripSlashes($_REQUEST);
3049                         if(isset($_COOKIE))
3050                                 $_COOKIE=$this->stripSlashes($_COOKIE);
3051                 }
3052                 $this->getApplication()->setRequest($this);
3053         }
3054         public function stripSlashes(&$data)
3055         {
3056                 return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
3057         }
3058         public function getUrl()
3059         {
3060                 if($this->_url===null)
3061                 {
3062                         $secure=$this->getIsSecureConnection();
3063                         $url=$secure?'https://':'http://';
3064                         if(empty($_SERVER['HTTP_HOST']))
3065                         {
3066                                 $url.=$_SERVER['SERVER_NAME'];
3067                                 $port=$_SERVER['SERVER_PORT'];
3068                                 if(($port!=80 && !$secure) || ($port!=443 && $secure))
3069                                         $url.=':'.$port;
3070                         }
3071                         else
3072                                 $url.=$_SERVER['HTTP_HOST'];
3073                         $url.=$this->getRequestUri();
3074                         $this->_url=new TUri($url);
3075                 }
3076                 return $this->_url;
3077         }
3078         public function setEnableCache($value)
3079         {
3080                 $this->_enableCache = TPropertyValue::ensureBoolean($value);
3081         }
3082         public function getEnableCache()
3083         {
3084                 return $this->_enableCache;
3085         }
3086         protected function getCacheKey()
3087         {
3088                 return $this->getID();
3089         }
3090         protected function cacheUrlManager($manager)
3091         {
3092                 if($this->getEnableCache())
3093                 {
3094                         $cache = $this->getApplication()->getCache();
3095                         if($cache !== null)
3096                         {
3097                                 $dependencies = null;
3098                                 if($this->getApplication()->getMode() !== TApplicationMode::Performance)
3099                                         if ($manager instanceof TUrlMapping && $fn = $manager->getConfigFile())
3100                                         {
3101                                                 $fn = Prado::getPathOfNamespace($fn,$this->getApplication()->getConfigurationFileExt());
3102                                                 $dependencies = new TFileCacheDependency($fn);
3103                                         }
3104                                 return $cache->set($this->getCacheKey(), $manager, 0, $dependencies);
3105                         }
3106                 }
3107                 return false;
3108         }
3109         protected function loadCachedUrlManager()
3110         {
3111                 if($this->getEnableCache())
3112                 {
3113                         $cache = $this->getApplication()->getCache();
3114                         if($cache !== null)
3115                         {
3116                                 $manager = $cache->get($this->getCacheKey());
3117                                 if($manager instanceof TUrlManager)
3118                                         return $manager;
3119                         }
3120                 }
3121                 return null;
3122         }
3123         public function getUrlManager()
3124         {
3125                 return $this->_urlManagerID;
3126         }
3127         public function setUrlManager($value)
3128         {
3129                 $this->_urlManagerID=$value;
3130         }
3131         public function getUrlManagerModule()
3132         {
3133                 if($this->_urlManager===null)
3134                 {
3135                         if(($this->_urlManager = $this->loadCachedUrlManager())===null)
3136                         {
3137                                 if(empty($this->_urlManagerID))
3138                                 {
3139                                         $this->_urlManager=new TUrlManager;
3140                                         $this->_urlManager->init(null);
3141                                 }
3142                                 else
3143                                 {
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);
3149                                 }
3150                                 $this->cacheUrlManager($this->_urlManager);
3151                         }
3152                 }
3153                 return $this->_urlManager;
3154         }
3155         public function getUrlFormat()
3156         {
3157                 return $this->_urlFormat;
3158         }
3159         public function setUrlFormat($value)
3160         {
3161                 $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
3162         }
3163         public function getUrlParamSeparator()
3164         {
3165                 return $this->_separator;
3166         }
3167         public function setUrlParamSeparator($value)
3168         {
3169                 if(strlen($value)===1)
3170                         $this->_separator=$value;
3171                 else
3172                         throw new TInvalidDataValueException('httprequest_separator_invalid');
3173         }
3174         public function getRequestType()
3175         {
3176                 return isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:null;
3177         }
3178         public function getContentType($mimetypeOnly = true)
3179         {
3180                 if(!isset($_SERVER['CONTENT_TYPE']))
3181                         return null;
3182                 if($mimetypeOnly === true && ($_pos = strpos(';', $_SERVER['CONTENT_TYPE'])) !== false)
3183                         return substr($_SERVER['CONTENT_TYPE'], 0, $_pos);
3184                 return $_SERVER['CONTENT_TYPE'];
3185         }
3186         public function getIsSecureConnection()
3187         {
3188                         return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
3189         }
3190         public function getPathInfo()
3191         {
3192                 return $this->_pathInfo;
3193         }
3194         public function getQueryString()
3195         {
3196                 return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:null;
3197         }
3198         public function getHttpProtocolVersion()
3199         {
3200                 return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:null;
3201         }
3202         public function getHeaders($case=null)
3203         {
3204                 static $result;
3205                 if($result === null && function_exists('apache_request_headers')) {
3206                         $result = apache_request_headers();
3207                 }
3208                 elseif($result === null) {
3209                         $result = array();
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;
3214                         }
3215                 }
3216                 if($case !== null)
3217                         return array_change_key_case($result, $case);
3218                 return $result;
3219         }
3220         public function getRequestUri()
3221         {
3222                 return $this->_requestUri;
3223         }
3224         public function getBaseUrl($forceSecureConnection=null)
3225         {
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;
3231         }
3232         public function getApplicationUrl()
3233         {
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;
3237         }
3238         public function getAbsoluteApplicationUrl($forceSecureConnection=null)
3239         {
3240                 return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
3241         }
3242         public function getApplicationFilePath()
3243         {
3244                 return realpath(isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:null);
3245         }
3246         public function getServerName()
3247         {
3248                 return isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:null;
3249         }
3250         public function getServerPort()
3251         {
3252                 return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null;
3253         }
3254         public function getUrlReferrer()
3255         {
3256                 return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
3257         }
3258         public function getBrowser()
3259         {
3260                 try
3261                 {
3262                         return get_browser();
3263                 }
3264                 catch(TPhpErrorException $e)
3265                 {
3266                         throw new TConfigurationException('httprequest_browscap_required');
3267                 }
3268         }
3269         public function getUserAgent()
3270         {
3271                 return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
3272         }
3273         public function getUserHostAddress()
3274         {
3275                 return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null;
3276         }
3277         public function getUserHost()
3278         {
3279                 return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
3280         }
3281         public function getAcceptTypes()
3282         {
3283                                 return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
3284         }
3285         public function getUserLanguages()
3286         {
3287                 return Prado::getUserLanguages();
3288         }
3289         public function getEnableCookieValidation()
3290         {
3291                 return $this->_enableCookieValidation;
3292         }
3293         public function setEnableCookieValidation($value)
3294         {
3295                 $this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
3296         }
3297         public function getCgiFix()
3298         {
3299                 return $this->_cgiFix;
3300         }
3301         public function setCgiFix($value)
3302         {
3303                 $this->_cgiFix=TPropertyValue::ensureInteger($value);
3304         }
3305         public function getCookies()
3306         {
3307                 if($this->_cookies===null)
3308                 {
3309                         $this->_cookies=new THttpCookieCollection;
3310                         if($this->getEnableCookieValidation())
3311                         {
3312                                 $sm=$this->getApplication()->getSecurityManager();
3313                                 foreach($_COOKIE as $key=>$value)
3314                                 {
3315                                         if(($value=$sm->validateData($value))!==false)
3316                                                 $this->_cookies->add(new THttpCookie($key,$value));
3317                                 }
3318                         }
3319                         else
3320                         {
3321                                 foreach($_COOKIE as $key=>$value)
3322                                         $this->_cookies->add(new THttpCookie($key,$value));
3323                         }
3324                 }
3325                 return $this->_cookies;
3326         }
3327         public function getUploadedFiles()
3328         {
3329                 return $_FILES;
3330         }
3331         public function getServerVariables()
3332         {
3333                 return $_SERVER;
3334         }
3335         public function getEnvironmentVariables()
3336         {
3337                 return $_ENV;
3338         }
3339         public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
3340         {
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?'&amp;':'&')) . SID;
3346                 else
3347                         return $url;
3348         }
3349         protected function parseUrl()
3350         {
3351                 return $this->getUrlManagerModule()->parseUrl();
3352         }
3353         public function resolveRequest($serviceIDs)
3354         {
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)
3361                 {
3362                         if($this->contains($serviceID))
3363                         {
3364                                 $this->setServiceID($serviceID);
3365                                 $this->setServiceParameter($this->itemAt($serviceID));
3366                                 return $serviceID;
3367                         }
3368                 }
3369                 return null;
3370         }
3371         public function getRequestResolved()
3372         {
3373                 return $this->_requestResolved;
3374         }
3375         public function getServiceID()
3376         {
3377                 return $this->_serviceID;
3378         }
3379         public function setServiceID($value)
3380         {
3381                 $this->_serviceID=$value;
3382         }
3383         public function getServiceParameter()
3384         {
3385                 return $this->_serviceParam;
3386         }
3387         public function setServiceParameter($value)
3388         {
3389                 $this->_serviceParam=$value;
3390         }
3391         public function getIterator()
3392         {
3393                 return new ArrayIterator($this->_items);
3394         }
3395         public function getCount()
3396         {
3397                 return count($this->_items);
3398         }
3399         public function count()
3400         {
3401                 return $this->getCount();
3402         }
3403         public function getKeys()
3404         {
3405                 return array_keys($this->_items);
3406         }
3407         public function itemAt($key)
3408         {
3409                 return isset($this->_items[$key]) ? $this->_items[$key] : null;
3410         }
3411         public function add($key,$value)
3412         {
3413                 $this->_items[$key]=$value;
3414         }
3415         public function remove($key)
3416         {
3417                 if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
3418                 {
3419                         $value=$this->_items[$key];
3420                         unset($this->_items[$key]);
3421                         return $value;
3422                 }
3423                 else
3424                         return null;
3425         }
3426         public function clear()
3427         {
3428                 foreach(array_keys($this->_items) as $key)
3429                         $this->remove($key);
3430         }
3431         public function contains($key)
3432         {
3433                 return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
3434         }
3435         public function toArray()
3436         {
3437                 return $this->_items;
3438         }
3439         public function offsetExists($offset)
3440         {
3441                 return $this->contains($offset);
3442         }
3443         public function offsetGet($offset)
3444         {
3445                 return $this->itemAt($offset);
3446         }
3447         public function offsetSet($offset,$item)
3448         {
3449                 $this->add($offset,$item);
3450         }
3451         public function offsetUnset($offset)
3452         {
3453                 $this->remove($offset);
3454         }
3455 }
3456 class THttpCookieCollection extends TList
3457 {
3458         private $_o;
3459         public function __construct($owner=null)
3460         {
3461                 $this->_o=$owner;
3462         }
3463         public function insertAt($index,$item)
3464         {
3465                 if($item instanceof THttpCookie)
3466                 {
3467                         parent::insertAt($index,$item);
3468                         if($this->_o instanceof THttpResponse)
3469                                 $this->_o->addCookie($item);
3470                 }
3471                 else
3472                         throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
3473         }
3474         public function removeAt($index)
3475         {
3476                 $item=parent::removeAt($index);
3477                 if($this->_o instanceof THttpResponse)
3478                         $this->_o->removeCookie($item);
3479                 return $item;
3480         }
3481         public function itemAt($index)
3482         {
3483                 if(is_integer($index))
3484                         return parent::itemAt($index);
3485                 else
3486                         return $this->findCookieByName($index);
3487         }
3488         public function findCookieByName($name)
3489         {
3490                 foreach($this as $cookie)
3491                         if($cookie->getName()===$name)
3492                                 return $cookie;
3493                 return null;
3494         }
3495 }
3496 class THttpCookie extends TComponent
3497 {
3498         private $_domain='';
3499         private $_name;
3500         private $_value='';
3501         private $_expire=0;
3502         private $_path='/';
3503         private $_secure=false;
3504         private $_httpOnly=false;
3505         public function __construct($name,$value)
3506         {
3507                 $this->_name=$name;
3508                 $this->_value=$value;
3509         }
3510         public function getDomain()
3511         {
3512                 return $this->_domain;
3513         }
3514         public function setDomain($value)
3515         {
3516                 $this->_domain=$value;
3517         }
3518         public function getExpire()
3519         {
3520                 return $this->_expire;
3521         }
3522         public function setExpire($value)
3523         {
3524                 $this->_expire=TPropertyValue::ensureInteger($value);
3525         }
3526         public function getHttpOnly()
3527         {
3528                 return $this->_httpOnly;
3529         }
3530         public function setHttpOnly($value)
3531         {
3532                 $this->_httpOnly = TPropertyValue::ensureBoolean($value);
3533         }
3534         public function getName()
3535         {
3536                 return $this->_name;
3537         }
3538         public function setName($value)
3539         {
3540                 $this->_name=$value;
3541         }
3542         public function getValue()
3543         {
3544                 return $this->_value;
3545         }
3546         public function setValue($value)
3547         {
3548                 $this->_value=$value;
3549         }
3550         public function getPath()
3551         {
3552                 return $this->_path;
3553         }
3554         public function setPath($value)
3555         {
3556                 $this->_path=$value;
3557         }
3558         public function getSecure()
3559         {
3560                 return $this->_secure;
3561         }
3562         public function setSecure($value)
3563         {
3564                 $this->_secure=TPropertyValue::ensureBoolean($value);
3565         }
3566 }
3567 class TUri extends TComponent
3568 {
3569         private static $_defaultPort=array(
3570                 'ftp'=>21,
3571                 'gopher'=>70,
3572                 'http'=>80,
3573                 'https'=>443,
3574                 'news'=>119,
3575                 'nntp'=>119,
3576                 'wais'=>210,
3577                 'telnet'=>23
3578         );
3579         private $_scheme;
3580         private $_host;
3581         private $_port;
3582         private $_user;
3583         private $_pass;
3584         private $_path;
3585         private $_query;
3586         private $_fragment;
3587         private $_uri;
3588         public function __construct($uri)
3589         {
3590                 if(($ret=@parse_url($uri))!==false)
3591                 {
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']:'';
3600                         $this->_uri=$uri;
3601                 }
3602                 else
3603                 {
3604                         throw new TInvalidDataValueException('uri_format_invalid',$uri);
3605                 }
3606         }
3607         public function getUri()
3608         {
3609                 return $this->_uri;
3610         }
3611         public function getScheme()
3612         {
3613                 return $this->_scheme;
3614         }
3615         public function getHost()
3616         {
3617                 return $this->_host;
3618         }
3619         public function getPort()
3620         {
3621                 return $this->_port;
3622         }
3623         public function getUser()
3624         {
3625                 return $this->_user;
3626         }
3627         public function getPassword()
3628         {
3629                 return $this->_pass;
3630         }
3631         public function getPath()
3632         {
3633                 return $this->_path;
3634         }
3635         public function getQuery()
3636         {
3637                 return $this->_query;
3638         }
3639         public function getFragment()
3640         {
3641                 return $this->_fragment;
3642         }
3643 }
3644 class THttpRequestUrlFormat extends TEnumerable
3645 {
3646         const Get='Get';
3647         const Path='Path';
3648         const HiddenPath='HiddenPath';
3649 }
3650 class THttpResponseAdapter extends TApplicationComponent
3651 {
3652         private $_response;
3653         public function __construct($response)
3654         {
3655                 $this->_response=$response;
3656         }
3657         public function getResponse()
3658         {
3659                 return $this->_response;
3660         }
3661         public function flushContent()
3662         {
3663                 $this->_response->flushContent();
3664         }
3665         public function httpRedirect($url)
3666         {
3667                 $this->_response->httpRedirect($url);
3668         }
3669         public function createNewHtmlWriter($type, $writer)
3670         {
3671                 return $this->_response->createNewHtmlWriter($type,$writer);
3672         }
3673 }
3674 class THttpResponse extends TModule implements ITextWriter
3675 {
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'
3684         );
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='';
3693         private $_adapter;
3694         private $_httpHeaderSent;
3695         private $_contentTypeHeaderSent;
3696         public function __destruct()
3697         {
3698                                         }
3699         public function setAdapter(THttpResponseAdapter $adapter)
3700         {
3701                 $this->_adapter=$adapter;
3702         }
3703         public function getAdapter()
3704         {
3705                 return $this->_adapter;
3706         }
3707         public function getHasAdapter()
3708         {
3709                 return $this->_adapter!==null;
3710         }
3711         public function init($config)
3712         {
3713                 if($this->_bufferOutput)
3714                         ob_start();
3715                 $this->_initialized=true;
3716                 $this->getApplication()->setResponse($this);
3717         }
3718         public function getCacheExpire()
3719         {
3720                 return session_cache_expire();
3721         }
3722         public function setCacheExpire($value)
3723         {
3724                 session_cache_expire(TPropertyValue::ensureInteger($value));
3725         }
3726         public function getCacheControl()
3727         {
3728                 return session_cache_limiter();
3729         }
3730         public function setCacheControl($value)
3731         {
3732                 session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
3733         }
3734         public function setContentType($type)
3735         {
3736                 if ($this->_contentTypeHeaderSent)
3737                         throw new Exception('Unable to alter content-type as it has been already sent');
3738                 $this->_contentType = $type;
3739         }
3740         public function getContentType()
3741         {
3742                 return $this->_contentType;
3743         }
3744         public function getCharset()
3745         {
3746                 return $this->_charset;
3747         }
3748         public function setCharset($charset)
3749         {
3750                 $this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
3751         }
3752         public function getBufferOutput()
3753         {
3754                 return $this->_bufferOutput;
3755         }
3756         public function setBufferOutput($value)
3757         {
3758                 if($this->_initialized)
3759                         throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
3760                 else
3761                         $this->_bufferOutput=TPropertyValue::ensureBoolean($value);
3762         }
3763         public function getStatusCode()
3764         {
3765                 return $this->_status;
3766         }
3767         public function setStatusCode($status, $reason=null)
3768         {
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];
3774                 }else{
3775                         if($reason===null || $reason==='') {
3776                                 throw new TInvalidDataValueException("response_status_reason_missing");
3777                         }
3778                         $reason=TPropertyValue::ensureString($reason);
3779                         if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
3780                                 throw new TInvalidDataValueException("response_status_reason_barchars");
3781                         }
3782                         $this->_reason=$reason;
3783                 }
3784                 $this->_status=$status;
3785         }
3786         public function getStatusReason() {
3787                 return $this->_reason;
3788         }
3789         public function getCookies()
3790         {
3791                 if($this->_cookies===null)
3792                         $this->_cookies=new THttpCookieCollection($this);
3793                 return $this->_cookies;
3794         }
3795         public function write($str)
3796         {
3797                                 if (!$this->_bufferOutput and !$this->_httpHeaderSent)
3798                         $this->ensureHeadersSent();
3799                 echo $str;
3800         }
3801         public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
3802         {
3803                 static $defaultMimeTypes=array(
3804                         'css'=>'text/css',
3805                         'gif'=>'image/gif',
3806                         'png'=>'image/png',
3807                         'jpg'=>'image/jpeg',
3808                         'jpeg'=>'image/jpeg',
3809                         'htm'=>'text/html',
3810                         'html'=>'text/html',
3811                         'js'=>'javascript/js',
3812                         'pdf'=>'application/pdf',
3813                         'xls'=>'application/vnd.ms-excel',
3814                 );
3815                 if($mimeType===null)
3816                 {
3817                         $mimeType='text/plain';
3818                         if(function_exists('mime_content_type'))
3819                                 $mimeType=mime_content_type($fileName);
3820                         else if(($ext=strrchr($fileName,'.'))!==false)
3821                         {
3822                                 $ext=substr($ext,1);
3823                                 if(isset($defaultMimeTypes[$ext]))
3824                                         $mimeType=$defaultMimeTypes[$ext];
3825                         }
3826                 }
3827                 if($clientFileName===null)
3828                         $clientFileName=basename($fileName);
3829                 else
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))
3835                 {
3836                         foreach($headers as $h)
3837                                 header($h);
3838                 }
3839                 else
3840                 {
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;
3846                 }
3847                 header('Content-Length: '.$fileSize);
3848                 header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
3849                 header('Content-Transfer-Encoding: binary');
3850                 if($content===null)
3851                         readfile($fileName);
3852                 else
3853                         echo $content;
3854         }
3855         public function redirect($url)
3856         {
3857                 if($this->getHasAdapter())
3858                         $this->_adapter->httpRedirect($url);
3859                 else
3860                         $this->httpRedirect($url);
3861         }
3862         public function httpRedirect($url)
3863         {
3864                 $this->ensureHeadersSent();
3865                 if($url[0]==='/')
3866                         $url=$this->getRequest()->getBaseUrl().$url;
3867                 if ($this->_status >= 300 && $this->_status < 400)
3868                                                 header('Location: '.str_replace('&amp;','&',$url), true, $this->_status);
3869                 else
3870                         header('Location: '.str_replace('&amp;','&',$url));
3871                 if(!$this->getApplication()->getRequestCompleted())
3872                         $this->getApplication()->onEndRequest();
3873                 exit();
3874         }
3875         public function reload()
3876         {
3877                 $this->redirect($this->getRequest()->getRequestUri());
3878         }
3879         public function flush($continueBuffering = true)
3880         {
3881                 if($this->getHasAdapter())
3882                         $this->_adapter->flushContent($continueBuffering);
3883                 else
3884                         $this->flushContent($continueBuffering);
3885         }
3886         public function ensureHeadersSent()
3887         {
3888                 $this->ensureHttpHeaderSent();
3889                 $this->ensureContentTypeHeaderSent();
3890         }
3891         public function flushContent($continueBuffering = true)
3892         {
3893                 $this->ensureHeadersSent();
3894                 if($this->_bufferOutput)
3895                 {
3896                                                 if (ob_get_length()>0)
3897                         {
3898                                 if (!$continueBuffering)
3899                                 {
3900                                         $this->_bufferOutput = false;
3901                                         ob_end_flush();
3902                                 }
3903                                 else
3904                                         ob_flush();
3905                                 flush();
3906                         }
3907                 }
3908                 else
3909                         flush();
3910         }
3911         protected function ensureHttpHeaderSent()
3912         {
3913                 if (!$this->_httpHeaderSent)
3914                         $this->sendHttpHeader();
3915         }
3916         protected function sendHttpHeader()
3917         {
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;
3925         }
3926         protected function ensureContentTypeHeaderSent()
3927         {
3928                 if (!$this->_contentTypeHeaderSent)
3929                         $this->sendContentTypeHeader();
3930         }
3931         protected function sendContentTypeHeader()
3932         {
3933                 $contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
3934                 $charset=$this->getCharset();
3935                 if($charset === false) {
3936                         $this->appendHeader('Content-Type: '.$contentType);
3937                         return;
3938                 }
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;
3944         }
3945         public function getContents()
3946         {
3947                 return $this->_bufferOutput?ob_get_contents():'';
3948         }
3949         public function clear()
3950         {
3951                 if($this->_bufferOutput)
3952                         ob_clean();
3953         }
3954         public function getHeaders($case=null)
3955         {
3956                 $result = array();
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;
3964                         else
3965                                 $result[$key] = $value;
3966                 }
3967                 if($case !== null)
3968                         return array_change_key_case($result, $case);
3969                 return $result;
3970         }
3971         public function appendHeader($value, $replace=true)
3972         {
3973                 header($value, $replace);
3974         }
3975         public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
3976         {
3977                 error_log($message,$messageType,$destination,$extraHeaders);
3978         }
3979         public function addCookie($cookie)
3980         {
3981                 $request=$this->getRequest();
3982                 if($request->getEnableCookieValidation())
3983                 {
3984                         $value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
3985                         setcookie(
3986                                 $cookie->getName(),
3987                                 $value,
3988                                 $cookie->getExpire(),
3989                                 $cookie->getPath(),
3990                                 $cookie->getDomain(),
3991                                 $cookie->getSecure(),
3992                                 $cookie->getHttpOnly()
3993                         );
3994                 }
3995                 else {
3996                         setcookie(
3997                                 $cookie->getName(),
3998                                 $cookie->getValue(),
3999                                 $cookie->getExpire(),
4000                                 $cookie->getPath(),
4001                                 $cookie->getDomain(),
4002                                 $cookie->getSecure(),
4003                                 $cookie->getHttpOnly()
4004                         );
4005                 }
4006         }
4007         public function removeCookie($cookie)
4008         {
4009                 setcookie(
4010                         $cookie->getName(),
4011                         null,
4012                         0,
4013                         $cookie->getPath(),
4014                         $cookie->getDomain(),
4015                         $cookie->getSecure(),
4016                         $cookie->getHttpOnly()
4017                 );
4018         }
4019         public function getHtmlWriterType()
4020         {
4021                 return $this->_htmlWriterType;
4022         }
4023         public function setHtmlWriterType($value)
4024         {
4025                 $this->_htmlWriterType=$value;
4026         }
4027         public function createHtmlWriter($type=null)
4028         {
4029                 if($type===null)
4030                         $type=$this->getHtmlWriterType();
4031                 if($this->getHasAdapter())
4032                         return $this->_adapter->createNewHtmlWriter($type, $this);
4033                 else
4034                         return $this->createNewHtmlWriter($type, $this);
4035         }
4036         public function createNewHtmlWriter($type, $writer)
4037         {
4038                 return Prado::createComponent($type, $writer);
4039         }
4040 }
4041 class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
4042 {
4043         private $_initialized=false;
4044         private $_started=false;
4045         private $_autoStart=false;
4046         private $_cookie=null;
4047         private $_id;
4048         private $_customStorage=false;
4049         public function getID()
4050         {
4051                 return $this->_id;
4052         }
4053         public function setID($value)
4054         {
4055                 $this->_id=$value;
4056         }
4057         public function init($config)
4058         {
4059                 if($this->_autoStart)
4060                         $this->open();
4061                 $this->_initialized=true;
4062                 $this->getApplication()->setSession($this);
4063                 register_shutdown_function(array($this, "close"));
4064         }
4065         public function open()
4066         {
4067                 if(!$this->_started)
4068                 {
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')
4074                                 session_start();
4075                         $this->_started=true;
4076                 }
4077         }
4078         public function close()
4079         {
4080                 if($this->_started)
4081                 {
4082                         session_write_close();
4083                         $this->_started=false;
4084                 }
4085         }
4086         public function destroy()
4087         {
4088                 if($this->_started)
4089                 {
4090                         session_destroy();
4091                         $this->_started=false;
4092                 }
4093         }
4094         public function regenerate($deleteOld=false)
4095         {
4096                 $old = $this->getSessionID();
4097                 session_regenerate_id($deleteOld);
4098                 return $old;
4099         }
4100         public function getIsStarted()
4101         {
4102                 return $this->_started;
4103         }
4104         public function getSessionID()
4105         {
4106                 return session_id();
4107         }
4108         public function setSessionID($value)
4109         {
4110                 if($this->_started)
4111                         throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
4112                 else
4113                         session_id($value);
4114         }
4115         public function getSessionName()
4116         {
4117                 return session_name();
4118         }
4119         public function setSessionName($value)
4120         {
4121                 if($this->_started)
4122                         throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
4123                 else if(ctype_alnum($value))
4124                         session_name($value);
4125                 else
4126                         throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
4127         }
4128         public function getSavePath()
4129         {
4130                 return session_save_path();
4131         }
4132         public function setSavePath($value)
4133         {
4134                 if($this->_started)
4135                         throw new TInvalidOperationException('httpsession_savepath_unchangeable');
4136                 else if(is_dir($value))
4137                         session_save_path($value);
4138                 else
4139                         throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
4140         }
4141         public function getUseCustomStorage()
4142         {
4143                 return $this->_customStorage;
4144         }
4145         public function setUseCustomStorage($value)
4146         {
4147                 $this->_customStorage=TPropertyValue::ensureBoolean($value);
4148         }
4149         public function getCookie()
4150         {
4151                 if($this->_cookie===null)
4152                         $this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
4153                 return $this->_cookie;
4154         }
4155         public function getCookieMode()
4156         {
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;
4161                 else
4162                         return THttpSessionCookieMode::Only;
4163         }
4164         public function setCookieMode($value)
4165         {
4166                 if($this->_started)
4167                         throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
4168                 else
4169                 {
4170                         $value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
4171                         if($value===THttpSessionCookieMode::None) 
4172       {
4173                                 ini_set('session.use_cookies','0');
4174                           ini_set('session.use_only_cookies','0');
4175       }
4176                         else if($value===THttpSessionCookieMode::Allow)
4177                         {
4178                                 ini_set('session.use_cookies','1');
4179                                 ini_set('session.use_only_cookies','0');
4180                         }
4181                         else
4182                         {
4183                                 ini_set('session.use_cookies','1');
4184                                 ini_set('session.use_only_cookies','1');
4185                                 ini_set('session.use_trans_sid', 0);
4186                         }
4187                 }
4188         }
4189         public function getAutoStart()
4190         {
4191                 return $this->_autoStart;
4192         }
4193         public function setAutoStart($value)
4194         {
4195                 if($this->_initialized)
4196                         throw new TInvalidOperationException('httpsession_autostart_unchangeable');
4197                 else
4198                         $this->_autoStart=TPropertyValue::ensureBoolean($value);
4199         }
4200         public function getGCProbability()
4201         {
4202                 return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
4203         }
4204         public function setGCProbability($value)
4205         {
4206                 if($this->_started)
4207                         throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
4208                 else
4209                 {
4210                         $value=TPropertyValue::ensureInteger($value);
4211                         if($value>=0 && $value<=100)
4212                         {
4213                                 ini_set('session.gc_probability',$value);
4214                                 ini_set('session.gc_divisor','100');
4215                         }
4216                         else
4217                                 throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
4218                 }
4219         }
4220         public function getUseTransparentSessionID()
4221         {
4222                 return ini_get('session.use_trans_sid')==='1';
4223         }
4224         public function setUseTransparentSessionID($value)
4225         {
4226                 if($this->_started)
4227                         throw new TInvalidOperationException('httpsession_transid_unchangeable');
4228                 else
4229                 {
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');
4234                 }
4235         }
4236         public function getTimeout()
4237         {
4238                 return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
4239         }
4240         public function setTimeout($value)
4241         {
4242                 if($this->_started)
4243                         throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
4244                 else
4245                         ini_set('session.gc_maxlifetime',$value);
4246         }
4247         public function _open($savePath,$sessionName)
4248         {
4249                 return true;
4250         }
4251         public function _close()
4252         {
4253                 return true;
4254         }
4255         public function _read($id)
4256         {
4257                 return '';
4258         }
4259         public function _write($id,$data)
4260         {
4261                 return true;
4262         }
4263         public function _destroy($id)
4264         {
4265                 return true;
4266         }
4267         public function _gc($maxLifetime)
4268         {
4269                 return true;
4270         }
4271         public function getIterator()
4272         {
4273                 return new TSessionIterator;
4274         }
4275         public function getCount()
4276         {
4277                 return count($_SESSION);
4278         }
4279         public function count()
4280         {
4281                 return $this->getCount();
4282         }
4283         public function getKeys()
4284         {
4285                 return array_keys($_SESSION);
4286         }
4287         public function itemAt($key)
4288         {
4289                 return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
4290         }
4291         public function add($key,$value)
4292         {
4293                 $_SESSION[$key]=$value;
4294         }
4295         public function remove($key)
4296         {
4297                 if(isset($_SESSION[$key]))
4298                 {
4299                         $value=$_SESSION[$key];
4300                         unset($_SESSION[$key]);
4301                         return $value;
4302                 }
4303                 else
4304                         return null;
4305         }
4306         public function clear()
4307         {
4308                 foreach(array_keys($_SESSION) as $key)
4309                         unset($_SESSION[$key]);
4310         }
4311         public function contains($key)
4312         {
4313                 return isset($_SESSION[$key]);
4314         }
4315         public function toArray()
4316         {
4317                 return $_SESSION;
4318         }
4319         public function offsetExists($offset)
4320         {
4321                 return isset($_SESSION[$offset]);
4322         }
4323         public function offsetGet($offset)
4324         {
4325                 return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
4326         }
4327         public function offsetSet($offset,$item)
4328         {
4329                 $_SESSION[$offset]=$item;
4330         }
4331         public function offsetUnset($offset)
4332         {
4333                 unset($_SESSION[$offset]);
4334         }
4335 }
4336 class TSessionIterator implements Iterator
4337 {
4338         private $_keys;
4339         private $_key;
4340         public function __construct()
4341         {
4342                 $this->_keys=array_keys($_SESSION);
4343         }
4344         public function rewind()
4345         {
4346                 $this->_key=reset($this->_keys);
4347         }
4348         public function key()
4349         {
4350                 return $this->_key;
4351         }
4352         public function current()
4353         {
4354                 return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
4355         }
4356         public function next()
4357         {
4358                 do
4359                 {
4360                         $this->_key=next($this->_keys);
4361                 }
4362                 while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
4363         }
4364         public function valid()
4365         {
4366                 return $this->_key!==false;
4367         }
4368 }
4369 class THttpSessionCookieMode extends TEnumerable
4370 {
4371         const None='None';
4372         const Allow='Allow';
4373         const Only='Only';
4374 }
4375 Prado::using('System.Web.UI.WebControls.*');
4376 class TAttributeCollection extends TMap
4377 {
4378         private $_caseSensitive=false;
4379         protected function _getZappableSleepProps(&$exprops)
4380         {
4381                 parent::_getZappableSleepProps($exprops);
4382                 if ($this->_caseSensitive===false)
4383                         $exprops[] = "\0TAttributeCollection\0_caseSensitive";
4384         }
4385         public function __get($name)
4386         {
4387                 return $this->contains($name)?$this->itemAt($name):parent::__get($name);
4388         }
4389         public function __set($name,$value)
4390         {
4391                 $this->add($name,$value);
4392         }
4393         public function getCaseSensitive()
4394         {
4395                 return $this->_caseSensitive;
4396         }
4397         public function setCaseSensitive($value)
4398         {
4399                 $this->_caseSensitive=TPropertyValue::ensureBoolean($value);
4400         }
4401         public function itemAt($key)
4402         {
4403                 return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
4404         }
4405         public function add($key,$value)
4406         {
4407                 parent::add($this->_caseSensitive?$key:strtolower($key),$value);
4408         }
4409         public function remove($key)
4410         {
4411                 return parent::remove($this->_caseSensitive?$key:strtolower($key));
4412         }
4413         public function contains($key)
4414         {
4415                 return parent::contains($this->_caseSensitive?$key:strtolower($key));
4416         }
4417         public function hasProperty($name)
4418         {
4419                 return $this->contains($name) || parent::canGetProperty($name) || parent::canSetProperty($name);
4420         }
4421         public function canGetProperty($name)
4422         {
4423                 return $this->contains($name) || parent::canGetProperty($name);
4424         }
4425         public function canSetProperty($name)
4426         {
4427                 return true;
4428         }
4429 }
4430 class TControlAdapter extends TApplicationComponent
4431 {
4432         protected $_control;
4433         public function __construct($control)
4434         {
4435                 $this->_control=$control;
4436         }
4437         public function getControl()
4438         {
4439                 return $this->_control;
4440         }
4441         public function getPage()
4442         {
4443                 return $this->_control?$this->_control->getPage():null;
4444         }
4445         public function createChildControls()
4446         {
4447                 $this->_control->createChildControls();
4448         }
4449         public function loadState()
4450         {
4451                 $this->_control->loadState();
4452         }
4453         public function saveState()
4454         {
4455                 $this->_control->saveState();
4456         }
4457         public function onInit($param)
4458         {
4459                 $this->_control->onInit($param);
4460         }
4461         public function onLoad($param)
4462         {
4463                 $this->_control->onLoad($param);
4464         }
4465         public function onPreRender($param)
4466         {
4467                 $this->_control->onPreRender($param);
4468         }
4469         public function onUnload($param)
4470         {
4471                 $this->_control->onUnload($param);
4472         }
4473         public function render($writer)
4474         {
4475                 $this->_control->render($writer);
4476         }
4477         public function renderChildren($writer)
4478         {
4479                 $this->_control->renderChildren($writer);
4480         }
4481 }
4482 class TControl extends TApplicationComponent implements IRenderable, IBindable
4483 {
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;
4492         const CS_LOADED=4;
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;              
4502         private $_id='';
4503         private $_uid;
4504         private $_parent;
4505         private $_page;
4506         private $_namingContainer;
4507         private $_tplControl;
4508         private $_viewState=array();
4509         private $_tempState=array();
4510         private $_trackViewState=true;
4511         private $_stage=0;
4512         private $_flags=0;
4513         private $_rf=array();
4514         public function __get($name)
4515         {
4516                 if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
4517                         return $this->_rf[self::RF_NAMED_OBJECTS][$name];
4518                 else
4519                         return parent::__get($name);
4520         }
4521         public function __isset($name) {
4522                 if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) {
4523                         return true;
4524                 } else {
4525                         return parent::__isset($name);
4526                 }
4527         }
4528         public function getHasAdapter()
4529         {
4530                 return isset($this->_rf[self::RF_ADAPTER]);
4531         }
4532         public function getAdapter()
4533         {
4534                 return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
4535         }
4536         public function setAdapter(TControlAdapter $adapter)
4537         {
4538                 $this->_rf[self::RF_ADAPTER]=$adapter;
4539         }
4540         public function getParent()
4541         {
4542                 return $this->_parent;
4543         }
4544         public function getNamingContainer()
4545         {
4546                 if(!$this->_namingContainer && $this->_parent)
4547                 {
4548                         if($this->_parent instanceof INamingContainer)
4549                                 $this->_namingContainer=$this->_parent;
4550                         else
4551                                 $this->_namingContainer=$this->_parent->getNamingContainer();
4552                 }
4553                 return $this->_namingContainer;
4554         }
4555         public function getPage()
4556         {
4557                 if(!$this->_page)
4558                 {
4559                         if($this->_parent)
4560                                 $this->_page=$this->_parent->getPage();
4561                         else if($this->_tplControl)
4562                                 $this->_page=$this->_tplControl->getPage();
4563                 }
4564                 return $this->_page;
4565         }
4566         public function setPage($page)
4567         {
4568                 $this->_page=$page;
4569         }
4570         public function setTemplateControl($control)
4571         {
4572                 $this->_tplControl=$control;
4573         }
4574         public function getTemplateControl()
4575         {
4576                 if(!$this->_tplControl && $this->_parent)
4577                         $this->_tplControl=$this->_parent->getTemplateControl();
4578                 return $this->_tplControl;
4579         }
4580         public function getSourceTemplateControl()
4581         {
4582                 $control=$this;
4583                 while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
4584                 {
4585                         if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
4586                                 return $control;
4587                 }
4588                 return $this->getPage();
4589         }
4590         protected function getControlStage()
4591         {
4592                 return $this->_stage;
4593         }
4594         protected function setControlStage($value)
4595         {
4596                 $this->_stage=$value;
4597         }
4598         public function getID($hideAutoID=true)
4599         {
4600                 if($hideAutoID)
4601                         return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
4602                 else
4603                         return $this->_id;
4604         }
4605         public function setID($id)
4606         {
4607                 if(!preg_match(self::ID_FORMAT,$id))
4608                         throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
4609                 $this->_id=$id;
4610                 $this->_flags |= self::IS_ID_SET;
4611                 $this->clearCachedUniqueID($this instanceof INamingContainer);
4612                 if($this->_namingContainer)
4613                         $this->_namingContainer->clearNameTable();
4614         }
4615         public function getUniqueID()
4616         {
4617                 if($this->_uid==='' || $this->_uid===null)                      {
4618                         $this->_uid='';                         if($namingContainer=$this->getNamingContainer())
4619                         {
4620                                 if($this->getPage()===$namingContainer)
4621                                         return ($this->_uid=$this->_id);
4622                                 else if(($prefix=$namingContainer->getUniqueID())==='')
4623                                         return $this->_id;
4624                                 else
4625                                         return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
4626                         }
4627                         else                                    return $this->_id;
4628                 }
4629                 else
4630                         return $this->_uid;
4631         }
4632         public function focus()
4633         {
4634                 $this->getPage()->setFocus($this);
4635         }
4636         public function getClientID()
4637         {
4638                 return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4639         }
4640         public static function convertUniqueIdToClientId($uniqueID)
4641         {
4642                 return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4643         }
4644         public function getSkinID()
4645         {
4646                 return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
4647         }
4648         public function setSkinID($value)
4649         {
4650                 if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
4651                         throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
4652                 else
4653                         $this->_rf[self::RF_SKIN_ID]=$value;
4654         }
4655         public function getIsSkinApplied()
4656         {
4657                 return ($this->_flags & self::IS_SKIN_APPLIED);
4658         }
4659         public function getEnableTheming()
4660         {
4661                 if($this->_flags & self::IS_DISABLE_THEMING)
4662                         return false;
4663                 else
4664                         return $this->_parent?$this->_parent->getEnableTheming():true;
4665         }
4666         public function setEnableTheming($value)
4667         {
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;
4672                 else
4673                         $this->_flags |= self::IS_DISABLE_THEMING;
4674         }
4675         public function getCustomData()
4676         {
4677                 return $this->getViewState('CustomData',null);
4678         }
4679         public function setCustomData($value)
4680         {
4681                 $this->setViewState('CustomData',$value,null);
4682         }
4683         public function getHasControls()
4684         {
4685                 return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
4686         }
4687         public function getControls()
4688         {
4689                 if(!isset($this->_rf[self::RF_CONTROLS]))
4690                         $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
4691                 return $this->_rf[self::RF_CONTROLS];
4692         }
4693         protected function createControlCollection()
4694         {
4695                 return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
4696         }
4697         public function getVisible($checkParents=true)
4698         {
4699                 if($checkParents)
4700                 {
4701                         for($control=$this;$control;$control=$control->_parent)
4702                                 if(!$control->getVisible(false))
4703                                         return false;
4704                         return true;
4705                 }
4706                 else
4707                         return $this->getViewState('Visible',true);
4708         }
4709         public function setVisible($value)
4710         {
4711                 $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
4712         }
4713         public function getEnabled($checkParents=false)
4714         {
4715                 if($checkParents)
4716                 {
4717                         for($control=$this;$control;$control=$control->_parent)
4718                                 if(!$control->getViewState('Enabled',true))
4719                                         return false;
4720                         return true;
4721                 }
4722                 else
4723                         return $this->getViewState('Enabled',true);
4724         }
4725         public function setEnabled($value)
4726         {
4727                 $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
4728         }
4729         public function getHasAttributes()
4730         {
4731                 if($attributes=$this->getViewState('Attributes',null))
4732                         return $attributes->getCount()>0;
4733                 else
4734                         return false;
4735         }
4736         public function getAttributes()
4737         {
4738                 if($attributes=$this->getViewState('Attributes',null))
4739                         return $attributes;
4740                 else
4741                 {
4742                         $attributes=new TAttributeCollection;
4743                         $this->setViewState('Attributes',$attributes,null);
4744                         return $attributes;
4745                 }
4746         }
4747         public function hasAttribute($name)
4748         {
4749                 if($attributes=$this->getViewState('Attributes',null))
4750                         return $attributes->contains($name);
4751                 else
4752                         return false;
4753         }
4754         public function getAttribute($name)
4755         {
4756                 if($attributes=$this->getViewState('Attributes',null))
4757                         return $attributes->itemAt($name);
4758                 else
4759                         return null;
4760         }
4761         public function setAttribute($name,$value)
4762         {
4763                 $this->getAttributes()->add($name,$value);
4764         }
4765         public function removeAttribute($name)
4766         {
4767                 if($attributes=$this->getViewState('Attributes',null))
4768                         return $attributes->remove($name);
4769                 else
4770                         return null;
4771         }
4772         public function getEnableViewState($checkParents=false)
4773         {
4774                 if($checkParents)
4775                 {
4776                         for($control=$this;$control!==null;$control=$control->getParent())
4777                                 if($control->_flags & self::IS_DISABLE_VIEWSTATE)
4778                                         return false;
4779                         return true;
4780                 }
4781                 else
4782                         return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
4783         }
4784         public function setEnableViewState($value)
4785         {
4786                 if(TPropertyValue::ensureBoolean($value))
4787                         $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
4788                 else
4789                         $this->_flags |= self::IS_DISABLE_VIEWSTATE;
4790         }
4791         protected function getControlState($key,$defaultValue=null)
4792         {
4793                 return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
4794         }
4795         protected function setControlState($key,$value,$defaultValue=null)
4796         {
4797                 if($value===$defaultValue)
4798                         unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4799                 else
4800                         $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
4801         }
4802         protected function clearControlState($key)
4803         {
4804                 unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4805         }
4806         public function trackViewState($enabled)
4807         {
4808                 $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
4809         }
4810         public function getViewState($key,$defaultValue=null)
4811         {
4812                 if(isset($this->_viewState[$key]))
4813                         return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
4814                 else if(isset($this->_tempState[$key]))
4815                 {
4816                         if(is_object($this->_tempState[$key]) && $this->_trackViewState)
4817                                 $this->_viewState[$key]=$this->_tempState[$key];
4818                         return $this->_tempState[$key];
4819                 }
4820                 else
4821                         return $defaultValue;
4822         }
4823         public function setViewState($key,$value,$defaultValue=null)
4824         {
4825                 if($this->_trackViewState)
4826                 {
4827                         unset($this->_tempState[$key]);
4828                         $this->_viewState[$key]=$value;
4829                 }
4830                 else
4831                 {
4832                         unset($this->_viewState[$key]);
4833                         if($value===$defaultValue)
4834                                 unset($this->_tempState[$key]);
4835                         else
4836                                 $this->_tempState[$key]=$value;
4837                 }
4838         }
4839         public function clearViewState($key)
4840         {
4841                 unset($this->_viewState[$key]);
4842                 unset($this->_tempState[$key]);
4843         }
4844         public function bindProperty($name,$expression)
4845         {
4846                 $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
4847         }
4848         public function unbindProperty($name)
4849         {
4850                 unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
4851         }
4852         public function autoBindProperty($name,$expression)
4853         {
4854                 $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
4855         }
4856         public function dataBind()
4857         {
4858                 $this->dataBindProperties();
4859                 $this->onDataBinding(null);
4860                 $this->dataBindChildren();
4861         }
4862         protected function dataBindProperties()
4863         {
4864                 if(isset($this->_rf[self::RF_DATA_BINDINGS]))
4865                 {
4866                         if(($context=$this->getTemplateControl())===null)
4867                                 $context=$this;
4868                         foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
4869                                 $this->setSubProperty($property,$context->evaluateExpression($expression));
4870                 }
4871         }
4872         protected function autoDataBindProperties()
4873         {
4874                 if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
4875                 {
4876                         if(($context=$this->getTemplateControl())===null)
4877                                 $context=$this;
4878                         foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
4879                                 $this->setSubProperty($property,$context->evaluateExpression($expression));
4880                 }
4881         }
4882         protected function dataBindChildren()
4883         {
4884                 if(isset($this->_rf[self::RF_CONTROLS]))
4885                 {
4886                         foreach($this->_rf[self::RF_CONTROLS] as $control)
4887                                 if($control instanceof IBindable)
4888                                         $control->dataBind();
4889                 }
4890         }
4891         final protected function getChildControlsCreated()
4892         {
4893                 return ($this->_flags & self::IS_CHILD_CREATED)!==0;
4894         }
4895         final protected function setChildControlsCreated($value)
4896         {
4897                 if($value)
4898                         $this->_flags |= self::IS_CHILD_CREATED;
4899                 else
4900                 {
4901                         if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
4902                                 $this->getControls()->clear();
4903                         $this->_flags &= ~self::IS_CHILD_CREATED;
4904                 }
4905         }
4906         public function ensureChildControls()
4907         {
4908                 if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
4909                 {
4910                         try
4911                         {
4912                                 $this->_flags |= self::IS_CREATING_CHILD;
4913                                 if(isset($this->_rf[self::RF_ADAPTER]))
4914                                         $this->_rf[self::RF_ADAPTER]->createChildControls();
4915                                 else
4916                                         $this->createChildControls();
4917                                 $this->_flags &= ~self::IS_CREATING_CHILD;
4918                                 $this->_flags |= self::IS_CHILD_CREATED;
4919                         }
4920                         catch(Exception $e)
4921                         {
4922                                 $this->_flags &= ~self::IS_CREATING_CHILD;
4923                                 $this->_flags |= self::IS_CHILD_CREATED;
4924                                 throw $e;
4925                         }
4926                 }
4927         }
4928         public function createChildControls()
4929         {
4930         }
4931         public function findControl($id)
4932         {
4933                 $id=strtr($id,'.',self::ID_SEPARATOR);
4934                 $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
4935                 if(!$container || !$container->getHasControls())
4936                         return null;
4937                 if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
4938                 {
4939                         $container->_rf[self::RF_NAMED_CONTROLS]=array();
4940                         $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
4941                 }
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;
4944                 else
4945                 {
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);
4950                         else
4951                                 return null;
4952                 }
4953         }
4954         public function findControlsByType($type,$strict=true)
4955         {
4956                 $controls=array();
4957                 if($this->getHasControls())
4958                 {
4959                         foreach($this->_rf[self::RF_CONTROLS] as $control)
4960                         {
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));
4965                         }
4966                 }
4967                 return $controls;
4968         }
4969         public function findControlsByID($id)
4970         {
4971                 $controls=array();
4972                 if($this->getHasControls())
4973                 {
4974                         foreach($this->_rf[self::RF_CONTROLS] as $control)
4975                         {
4976                                 if($control instanceof TControl)
4977                                 {
4978                                         if($control->_id===$id)
4979                                                 $controls[]=$control;
4980                                         $controls=array_merge($controls,$control->findControlsByID($id));
4981                                 }
4982                         }
4983                 }
4984                 return $controls;
4985         }
4986         public function clearNamingContainer()
4987         {
4988                 unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
4989                 $this->clearNameTable();
4990         }
4991         public function registerObject($name,$object)
4992         {
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;
4996         }
4997         public function unregisterObject($name)
4998         {
4999                 unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5000         }
5001         public function isObjectRegistered($name)
5002         {
5003                 return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5004         }
5005         public function getHasChildInitialized()
5006         {
5007                 return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
5008         }
5009         public function getHasInitialized()
5010         {
5011                 return $this->getControlStage() >= self::CS_INITIALIZED;
5012         }
5013         public function getHasLoadedPostData()
5014         {
5015                 return $this->getControlStage() >= self::CS_STATE_LOADED;
5016         }
5017         public function getHasLoaded()
5018         {
5019                 return $this->getControlStage() >= self::CS_LOADED;
5020         }
5021         public function getHasPreRendered()
5022         {
5023                 return $this->getControlStage() >= self::CS_PRERENDERED;
5024         }
5025         public function getRegisteredObject($name)
5026         {
5027                 return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
5028         }
5029         public function getAllowChildControls()
5030         {
5031                 return true;
5032         }
5033         public function addParsedObject($object)
5034         {
5035                 $this->getControls()->add($object);
5036         }
5037         final protected function clearChildState()
5038         {
5039                 unset($this->_rf[self::RF_CHILD_STATE]);
5040         }
5041         final protected function isDescendentOf($ancestor)
5042         {
5043                 $control=$this;
5044                 while($control!==$ancestor && $control->_parent)
5045                         $control=$control->_parent;
5046                 return $control===$ancestor;
5047         }
5048         public function addedControl($control)
5049         {
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)
5056                 {
5057                         $control->_namingContainer=$namingContainer;
5058                         if($control->_id==='')
5059                                 $control->generateAutomaticID();
5060                         else
5061                                 $namingContainer->clearNameTable();
5062                         $control->clearCachedUniqueID($control instanceof INamingContainer);
5063                 }
5064                 if($this->_stage>=self::CS_CHILD_INITIALIZED)
5065                 {
5066                         $control->initRecursive($namingContainer);
5067                         if($this->_stage>=self::CS_STATE_LOADED)
5068                         {
5069                                 if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
5070                                 {
5071                                         $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
5072                                         unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
5073                                 }
5074                                 else
5075                                         $state=null;
5076                                 $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
5077                                 if($this->_stage>=self::CS_LOADED)
5078                                 {
5079                                         $control->loadRecursive();
5080                                         if($this->_stage>=self::CS_PRERENDERED)
5081                                                 $control->preRenderRecursive();
5082                                 }
5083                         }
5084                 }
5085         }
5086         public function removedControl($control)
5087         {
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))
5096                         $control->_id='';
5097                 else
5098                         unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
5099                 $control->clearCachedUniqueID(true);
5100         }
5101         protected function initRecursive($namingContainer=null)
5102         {
5103                 $this->ensureChildControls();
5104                 if($this->getHasControls())
5105                 {
5106                         if($this instanceof INamingContainer)
5107                                 $namingContainer=$this;
5108                         $page=$this->getPage();
5109                         foreach($this->_rf[self::RF_CONTROLS] as $control)
5110                         {
5111                                 if($control instanceof TControl)
5112                                 {
5113                                         $control->_namingContainer=$namingContainer;
5114                                         $control->_page=$page;
5115                                         if($control->_id==='' && $namingContainer)
5116                                                 $control->generateAutomaticID();
5117                                         $control->initRecursive($namingContainer);
5118                                 }
5119                         }
5120                 }
5121                 if($this->_stage<self::CS_INITIALIZED)
5122                 {
5123                         $this->_stage=self::CS_CHILD_INITIALIZED;
5124                         if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
5125                         {
5126                                 $page->applyControlSkin($this);
5127                                 $this->_flags |= self::IS_SKIN_APPLIED;
5128                         }
5129                         if(isset($this->_rf[self::RF_ADAPTER]))
5130                                 $this->_rf[self::RF_ADAPTER]->onInit(null);
5131                         else
5132                                 $this->onInit(null);
5133                         $this->_stage=self::CS_INITIALIZED;
5134                 }
5135         }
5136         protected function loadRecursive()
5137         {
5138                 if($this->_stage<self::CS_LOADED)
5139                 {
5140                         if(isset($this->_rf[self::RF_ADAPTER]))
5141                                 $this->_rf[self::RF_ADAPTER]->onLoad(null);
5142                         else
5143                                 $this->onLoad(null);
5144                 }
5145                 if($this->getHasControls())
5146                 {
5147                         foreach($this->_rf[self::RF_CONTROLS] as $control)
5148                         {
5149                                 if($control instanceof TControl)
5150                                         $control->loadRecursive();
5151                         }
5152                 }
5153                 if($this->_stage<self::CS_LOADED)
5154                         $this->_stage=self::CS_LOADED;
5155         }
5156         protected function preRenderRecursive()
5157         {
5158                 $this->autoDataBindProperties();
5159                 if($this->getVisible(false))
5160                 {
5161                         if(isset($this->_rf[self::RF_ADAPTER]))
5162                                 $this->_rf[self::RF_ADAPTER]->onPreRender(null);
5163                         else
5164                                 $this->onPreRender(null);
5165                         if($this->getHasControls())
5166                         {
5167                                 foreach($this->_rf[self::RF_CONTROLS] as $control)
5168                                 {
5169                                         if($control instanceof TControl)
5170                                                 $control->preRenderRecursive();
5171                                         else if($control instanceof TCompositeLiteral)
5172                                                 $control->evaluateDynamicContent();
5173                                 }
5174                         }
5175                 }
5176                 $this->_stage=self::CS_PRERENDERED;
5177         }
5178         protected function unloadRecursive()
5179         {
5180                 if(!($this->_flags & self::IS_ID_SET))
5181                         $this->_id='';
5182                 if($this->getHasControls())
5183                 {
5184                         foreach($this->_rf[self::RF_CONTROLS] as $control)
5185                                 if($control instanceof TControl)
5186                                         $control->unloadRecursive();
5187                 }
5188                 if(isset($this->_rf[self::RF_ADAPTER]))
5189                         $this->_rf[self::RF_ADAPTER]->onUnload(null);
5190                 else
5191                         $this->onUnload(null);
5192         }
5193         public function onInit($param)
5194         {
5195                 $this->raiseEvent('OnInit',$this,$param);
5196         }
5197         public function onLoad($param)
5198         {
5199                 $this->raiseEvent('OnLoad',$this,$param);
5200         }
5201         public function onDataBinding($param)
5202         {
5203                 $this->raiseEvent('OnDataBinding',$this,$param);
5204         }
5205         public function onUnload($param)
5206         {
5207                 $this->raiseEvent('OnUnload',$this,$param);
5208         }
5209         public function onPreRender($param)
5210         {
5211                 $this->raiseEvent('OnPreRender',$this,$param);
5212         }
5213         protected function raiseBubbleEvent($sender,$param)
5214         {
5215                 $control=$this;
5216                 while($control=$control->_parent)
5217                 {
5218                         if($control->bubbleEvent($sender,$param))
5219                                 break;
5220                 }
5221         }
5222         public function bubbleEvent($sender,$param)
5223         {
5224                 return false;
5225         }
5226         public function broadcastEvent($name,$sender,$param)
5227         {
5228                 $rootControl=(($page=$this->getPage())===null)?$this:$page;
5229                 $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
5230         }
5231         private function broadcastEventInternal($name,$sender,$param)
5232         {
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())
5238                 {
5239                         foreach($this->_rf[self::RF_CONTROLS] as $control)
5240                         {
5241                                 if($control instanceof TControl)
5242                                         $control->broadcastEventInternal($name,$sender,$param);
5243                         }
5244                 }
5245         }
5246         protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
5247         {
5248                 if($preCallback!==null)
5249                         call_user_func($preCallback,$this,$param);
5250                 if($this->getHasControls())
5251                 {
5252                         foreach($this->_rf[self::RF_CONTROLS] as $control)
5253                         {
5254                                 if($control instanceof TControl)
5255                                 {
5256                                         $control->traverseChildControls($param,$preCallback,$postCallback);
5257                                 }
5258                         }
5259                 }
5260                 if($postCallback!==null)
5261                         call_user_func($postCallback,$this,$param);
5262         }
5263         public function renderControl($writer)
5264         {
5265                 if($this instanceof IActiveControl || $this->getVisible(false))
5266                 {
5267                         if(isset($this->_rf[self::RF_ADAPTER]))
5268                                 $this->_rf[self::RF_ADAPTER]->render($writer);
5269                         else
5270                                 $this->render($writer);
5271                 }
5272         }
5273         public function render($writer)
5274         {
5275                 $this->renderChildren($writer);
5276         }
5277         public function renderChildren($writer)
5278         {
5279                 if($this->getHasControls())
5280                 {
5281                         foreach($this->_rf[self::RF_CONTROLS] as $control)
5282                         {
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);
5289                         }
5290                 }
5291         }
5292         public function saveState()
5293         {
5294         }
5295         public function loadState()
5296         {
5297         }
5298         protected function loadStateRecursive(&$state,$needViewState=true)
5299         {
5300                 if(is_array($state))
5301                 {
5302                                                                         $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5303                         if(isset($state[1]))
5304                         {
5305                                 $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
5306                                 unset($state[1]);
5307                         }
5308                         else
5309                                 unset($this->_rf[self::RF_CONTROLSTATE]);
5310                         if($needViewState)
5311                         {
5312                                 if(isset($state[0]))
5313                                         $this->_viewState=&$state[0];
5314                                 else
5315                                         $this->_viewState=array();
5316                         }
5317                         unset($state[0]);
5318                         if($this->getHasControls())
5319                         {
5320                                 foreach($this->_rf[self::RF_CONTROLS] as $control)
5321                                 {
5322                                         if($control instanceof TControl)
5323                                         {
5324                                                 if(isset($state[$control->_id]))
5325                                                 {
5326                                                         $control->loadStateRecursive($state[$control->_id],$needViewState);
5327                                                         unset($state[$control->_id]);
5328                                                 }
5329                                         }
5330                                 }
5331                         }
5332                         if(!empty($state))
5333                                 $this->_rf[self::RF_CHILD_STATE]=&$state;
5334                 }
5335                 $this->_stage=self::CS_STATE_LOADED;
5336                 if(isset($this->_rf[self::RF_ADAPTER]))
5337                         $this->_rf[self::RF_ADAPTER]->loadState();
5338                 else
5339                         $this->loadState();
5340         }
5341         protected function &saveStateRecursive($needViewState=true)
5342         {
5343                 if(isset($this->_rf[self::RF_ADAPTER]))
5344                         $this->_rf[self::RF_ADAPTER]->saveState();
5345                 else
5346                         $this->saveState();
5347                 $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5348                 $state=array();
5349                 if($this->getHasControls())
5350                 {
5351                         foreach($this->_rf[self::RF_CONTROLS] as $control)
5352                         {
5353                                 if($control instanceof TControl)
5354                                 {
5355                                         if(count($tmp = &$control->saveStateRecursive($needViewState)))
5356                                                 $state[$control->_id]=$tmp;
5357                                 }
5358                         }
5359                 }
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];
5364                 return $state;
5365         }
5366         public function applyStyleSheetSkin($page)
5367         {
5368                 if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
5369                 {
5370                         $page->applyControlStyleSheet($this);
5371                         $this->_flags |= self::IS_STYLESHEET_APPLIED;
5372                 }
5373                 else if($this->_flags & self::IS_STYLESHEET_APPLIED)
5374                         throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
5375         }
5376         private function clearCachedUniqueID($recursive)
5377         {
5378                 if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
5379                 {
5380                         foreach($this->_rf[self::RF_CONTROLS] as $control)
5381                                 if($control instanceof TControl)
5382                                         $control->clearCachedUniqueID($recursive);
5383                 }
5384                 $this->_uid=null;
5385         }
5386         private function generateAutomaticID()
5387         {
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();
5394         }
5395         private function clearNameTable()
5396         {
5397                 unset($this->_rf[self::RF_NAMED_CONTROLS]);
5398         }
5399         private function fillNameTable($container,$controls)
5400         {
5401                 foreach($controls as $control)
5402                 {
5403                         if($control instanceof TControl)
5404                         {
5405                                 if($control->_id!=='')
5406                                 {
5407                                         if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
5408                                                 throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
5409                                         else
5410                                                 $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
5411                                 }
5412                                 if(!($control instanceof INamingContainer) && $control->getHasControls())
5413                                         $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
5414                         }
5415                 }
5416         }
5417 }
5418 class TControlCollection extends TList
5419 {
5420         private $_o;
5421         public function __construct(TControl $owner,$readOnly=false)
5422         {
5423                 $this->_o=$owner;
5424                 parent::__construct(null,$readOnly);
5425         }
5426         protected function getOwner()
5427         {
5428                 return $this->_o;
5429         }
5430         public function insertAt($index,$item)
5431         {
5432                 if($item instanceof TControl)
5433                 {
5434                         parent::insertAt($index,$item);
5435                         $this->_o->addedControl($item);
5436                 }
5437                 else if(is_string($item) || ($item instanceof IRenderable))
5438                         parent::insertAt($index,$item);
5439                 else
5440                         throw new TInvalidDataTypeException('controlcollection_control_required');
5441         }
5442         public function removeAt($index)
5443         {
5444                 $item=parent::removeAt($index);
5445                 if($item instanceof TControl)
5446                         $this->_o->removedControl($item);
5447                 return $item;
5448         }
5449         public function clear()
5450         {
5451                 parent::clear();
5452                 if($this->_o instanceof INamingContainer)
5453                         $this->_o->clearNamingContainer();
5454         }
5455 }
5456 class TEmptyControlCollection extends TControlCollection
5457 {
5458         public function __construct(TControl $owner)
5459         {
5460                 parent::__construct($owner,true);
5461         }
5462         public function insertAt($index,$item)
5463         {
5464                 if(!is_string($item))                   parent::insertAt($index,$item);         }
5465 }
5466 interface INamingContainer
5467 {
5468 }
5469 interface IPostBackEventHandler
5470 {
5471         public function raisePostBackEvent($param);
5472 }
5473 interface IPostBackDataHandler
5474 {
5475         public function loadPostData($key,$values);
5476         public function raisePostDataChangedEvent();
5477         public function getDataChanged();
5478 }
5479 interface IValidator
5480 {
5481         public function validate();
5482         public function getIsValid();
5483         public function setIsValid($value);
5484         public function getErrorMessage();
5485         public function setErrorMessage($value);
5486 }
5487 interface IValidatable
5488 {
5489         public function getValidationPropertyValue();
5490         public function getIsValid();
5491         public function setIsValid($value);
5492 }
5493 interface IBroadcastEventReceiver
5494 {
5495         public function broadcastEventReceived($sender,$param);
5496 }
5497 interface ITheme
5498 {
5499         public function applySkin($control);
5500 }
5501 interface ITemplate
5502 {
5503         public function instantiateIn($parent);
5504 }
5505 interface IButtonControl
5506 {
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();
5521 }
5522 interface ISurroundable
5523 {
5524         public function getSurroundingTag();
5525         public function getSurroundingTagID();
5526 }
5527 class TBroadcastEventParameter extends TEventParameter
5528 {
5529         private $_name;
5530         private $_param;
5531         public function __construct($name='',$parameter=null)
5532         {
5533                 $this->_name=$name;
5534                 $this->_param=$parameter;
5535         }
5536         public function getName()
5537         {
5538                 return $this->_name;
5539         }
5540         public function setName($value)
5541         {
5542                 $this->_name=$value;
5543         }
5544         public function getParameter()
5545         {
5546                 return $this->_param;
5547         }
5548         public function setParameter($value)
5549         {
5550                 $this->_param=$value;
5551         }
5552 }
5553 class TCommandEventParameter extends TEventParameter
5554 {
5555         private $_name;
5556         private $_param;
5557         public function __construct($name='',$parameter='')
5558         {
5559                 $this->_name=$name;
5560                 $this->_param=$parameter;
5561         }
5562         public function getCommandName()
5563         {
5564                 return $this->_name;
5565         }
5566         public function getCommandParameter()
5567         {
5568                 return $this->_param;
5569         }
5570 }
5571 class TCompositeLiteral extends TComponent implements IRenderable, IBindable
5572 {
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)
5582         {
5583                 $this->_items=array();
5584                 $this->_expressions=array();
5585                 $this->_statements=array();
5586                 foreach($items as $id=>$item)
5587                 {
5588                         if(is_array($item))
5589                         {
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]='';
5597                         }
5598                         else
5599                                 $this->_items[$id]=$item;
5600                 }
5601         }
5602         public function getContainer()
5603         {
5604                 return $this->_container;
5605         }
5606         public function setContainer(TComponent $value)
5607         {
5608                 $this->_container=$value;
5609         }
5610         public function evaluateDynamicContent()
5611         {
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);
5617         }
5618         public function dataBind()
5619         {
5620                 $context=$this->_container===null?$this:$this->_container;
5621                 foreach($this->_bindings as $id=>$binding)
5622                         $this->_items[$id]=$context->evaluateExpression($binding);
5623         }
5624         public function render($writer)
5625         {
5626                 $writer->write(implode('',$this->_items));
5627         }
5628 }
5629 class TFont extends TComponent
5630 {
5631         const IS_BOLD=0x01;
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;
5643         private $_flags=0;
5644         private $_name='';
5645         private $_size='';
5646         protected function _getZappableSleepProps(&$exprops)
5647         {
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";
5655         }
5656         public function getBold()
5657         {
5658                 return ($this->_flags & self::IS_BOLD)!==0;
5659         }
5660         public function setBold($value)
5661         {
5662                 $this->_flags |= self::IS_SET_BOLD;
5663                 if(TPropertyValue::ensureBoolean($value))
5664                         $this->_flags |= self::IS_BOLD;
5665                 else
5666                         $this->_flags &= ~self::IS_BOLD;
5667         }
5668         public function getItalic()
5669         {
5670                 return ($this->_flags & self::IS_ITALIC)!==0;
5671         }
5672         public function setItalic($value)
5673         {
5674                 $this->_flags |= self::IS_SET_ITALIC;
5675                 if(TPropertyValue::ensureBoolean($value))
5676                         $this->_flags |= self::IS_ITALIC;
5677                 else
5678                         $this->_flags &= ~self::IS_ITALIC;
5679         }
5680         public function getOverline()
5681         {
5682                 return ($this->_flags & self::IS_OVERLINE)!==0;
5683         }
5684         public function setOverline($value)
5685         {
5686                 $this->_flags |= self::IS_SET_OVERLINE;
5687                 if(TPropertyValue::ensureBoolean($value))
5688                         $this->_flags |= self::IS_OVERLINE;
5689                 else
5690                         $this->_flags &= ~self::IS_OVERLINE;
5691         }
5692         public function getSize()
5693         {
5694                 return $this->_size;
5695         }
5696         public function setSize($value)
5697         {
5698                 $this->_flags |= self::IS_SET_SIZE;
5699                 $this->_size=$value;
5700         }
5701         public function getStrikeout()
5702         {
5703                 return ($this->_flags & self::IS_STRIKEOUT)!==0;
5704         }
5705         public function setStrikeout($value)
5706         {
5707                 $this->_flags |= self::IS_SET_STRIKEOUT;
5708                 if(TPropertyValue::ensureBoolean($value))
5709                         $this->_flags |= self::IS_STRIKEOUT;
5710                 else
5711                         $this->_flags &= ~self::IS_STRIKEOUT;
5712         }
5713         public function getUnderline()
5714         {
5715                 return ($this->_flags & self::IS_UNDERLINE)!==0;
5716         }
5717         public function setUnderline($value)
5718         {
5719                 $this->_flags |= self::IS_SET_UNDERLINE;
5720                 if(TPropertyValue::ensureBoolean($value))
5721                         $this->_flags |= self::IS_UNDERLINE;
5722                 else
5723                         $this->_flags &= ~self::IS_UNDERLINE;
5724         }
5725         public function getName()
5726         {
5727                 return $this->_name;
5728         }
5729         public function setName($value)
5730         {
5731                 $this->_flags |= self::IS_SET_NAME;
5732                 $this->_name=$value;
5733         }
5734         public function getIsEmpty()
5735         {
5736                 return !$this->_flags;
5737         }
5738         public function reset()
5739         {
5740                 $this->_flags=0;
5741                 $this->_name='';
5742                 $this->_size='';
5743         }
5744         public function mergeWith($font)
5745         {
5746                 if($font===null || $font->_flags===0)
5747                         return;
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());
5762         }
5763         public function copyFrom($font)
5764         {
5765                 if($font===null || $font->_flags===0)
5766                         return;
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());
5781         }
5782         public function toString()
5783         {
5784                 if($this->_flags===0)
5785                         return '';
5786                 $str='';
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;');
5791                 $textDec='';
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);
5799                 if($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.';';
5805                 return $str;
5806         }
5807         public function addAttributesToRender($writer)
5808         {
5809                 if($this->_flags===0)
5810                         return;
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'));
5815                 $textDec='';
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);
5823                 if($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);
5829         }
5830 }
5831 class TStyle extends TComponent
5832 {
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)
5839         {
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";
5851         }
5852         public function __construct($style=null)
5853         {
5854     parent::__construct();
5855                 if($style!==null)
5856                         $this->copyFrom($style);
5857         }
5858         public function __clone()
5859         {
5860                 if($this->_font!==null)
5861                         $this->_font = clone($this->_font);
5862         }
5863         public function getBackColor()
5864         {
5865                 return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
5866         }
5867         public function setBackColor($value)
5868         {
5869                 if(trim($value)==='')
5870                         unset($this->_fields['background-color']);
5871                 else
5872                         $this->_fields['background-color']=$value;
5873         }
5874         public function getBorderColor()
5875         {
5876                 return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
5877         }
5878         public function setBorderColor($value)
5879         {
5880                 if(trim($value)==='')
5881                         unset($this->_fields['border-color']);
5882                 else
5883                         $this->_fields['border-color']=$value;
5884         }
5885         public function getBorderStyle()
5886         {
5887                 return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
5888         }
5889         public function setBorderStyle($value)
5890         {
5891                 if(trim($value)==='')
5892                         unset($this->_fields['border-style']);
5893                 else
5894                         $this->_fields['border-style']=$value;
5895         }
5896         public function getBorderWidth()
5897         {
5898                 return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
5899         }
5900         public function setBorderWidth($value)
5901         {
5902                 if(trim($value)==='')
5903                         unset($this->_fields['border-width']);
5904                 else
5905                         $this->_fields['border-width']=$value;
5906         }
5907         public function getCssClass()
5908         {
5909                 return $this->_class===null?'':$this->_class;
5910         }
5911         public function hasCssClass()
5912         {
5913                 return ($this->_class!==null);
5914         }
5915         public function setCssClass($value)
5916         {
5917                 $this->_class=$value;
5918         }
5919         public function getFont()
5920         {
5921                 if($this->_font===null)
5922                         $this->_font=new TFont;
5923                 return $this->_font;
5924         }
5925         public function hasFont()
5926         {
5927                 return $this->_font !== null;
5928         }
5929         public function setDisplayStyle($value)
5930         {
5931                 $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
5932                 switch($this->_displayStyle)
5933                 {
5934                         case TDisplayStyle::None:
5935                                 $this->_fields['display'] = 'none';
5936                                 break;
5937                         case TDisplayStyle::Dynamic:
5938                                 $this->_fields['display'] = '';                                 break;
5939                         case TDisplayStyle::Fixed:
5940                                 $this->_fields['visibility'] = 'visible';
5941                                 break;
5942                         case TDisplayStyle::Hidden:
5943                                 $this->_fields['visibility'] = 'hidden';
5944                                 break;
5945                 }
5946         }
5947         public function getDisplayStyle()
5948         {
5949                 return $this->_displayStyle;
5950         }
5951         public function getForeColor()
5952         {
5953                 return isset($this->_fields['color'])?$this->_fields['color']:'';
5954         }
5955         public function setForeColor($value)
5956         {
5957                 if(trim($value)==='')
5958                         unset($this->_fields['color']);
5959                 else
5960                         $this->_fields['color']=$value;
5961         }
5962         public function getHeight()
5963         {
5964                 return isset($this->_fields['height'])?$this->_fields['height']:'';
5965         }
5966         public function setHeight($value)
5967         {
5968                 if(trim($value)==='')
5969                         unset($this->_fields['height']);
5970                 else
5971                         $this->_fields['height']=$value;
5972         }
5973         public function getCustomStyle()
5974         {
5975                 return $this->_customStyle===null?'':$this->_customStyle;
5976         }
5977         public function setCustomStyle($value)
5978         {
5979                 $this->_customStyle=$value;
5980         }
5981         public function getStyleField($name)
5982         {
5983                 return isset($this->_fields[$name])?$this->_fields[$name]:'';
5984         }
5985         public function setStyleField($name,$value)
5986         {
5987                 $this->_fields[$name]=$value;
5988         }
5989         public function clearStyleField($name)
5990         {
5991                 unset($this->_fields[$name]);
5992         }
5993         public function hasStyleField($name)
5994         {
5995                 return isset($this->_fields[$name]);
5996         }
5997         public function getWidth()
5998         {
5999                 return isset($this->_fields['width'])?$this->_fields['width']:'';
6000         }
6001         public function setWidth($value)
6002         {
6003                 $this->_fields['width']=$value;
6004         }
6005         public function reset()
6006         {
6007                 $this->_fields=array();
6008                 $this->_font=null;
6009                 $this->_class=null;
6010                 $this->_customStyle=null;
6011         }
6012         public function copyFrom($style)
6013         {
6014                 if($style instanceof TStyle)
6015                 {
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);
6023                 }
6024         }
6025         public function mergeWith($style)
6026         {
6027                 if($style instanceof TStyle)
6028                 {
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);
6036                 }
6037         }
6038         public function addAttributesToRender($writer)
6039         {
6040                 if($this->_customStyle!==null)
6041                 {
6042                         foreach(explode(';',$this->_customStyle) as $style)
6043                         {
6044                                 $arr=explode(':',$style,2);
6045                                 if(isset($arr[1]) && trim($arr[0])!=='')
6046                                         $writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
6047                         }
6048                 }
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);
6054         }
6055         public function getStyleFields()
6056         {
6057                 return $this->_fields;
6058         }
6059 }
6060 class TDisplayStyle extends TEnumerable
6061 {
6062         const None='None';
6063         const Dynamic='Dynamic';
6064         const Fixed='Fixed';
6065         const Hidden='Hidden';
6066 }
6067 class TTableStyle extends TStyle
6068 {
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)
6076         {
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";
6090         }
6091         public function reset()
6092         {
6093                 $this->_backImageUrl=null;
6094                 $this->_horizontalAlign=null;
6095                 $this->_cellPadding=null;
6096                 $this->_cellSpacing=null;
6097                 $this->_gridLines=null;
6098                 $this->_borderCollapse=null;
6099         }
6100         public function copyFrom($style)
6101         {
6102                 parent::copyFrom($style);
6103                 if($style instanceof TTableStyle)
6104                 {
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;
6117                 }
6118         }
6119         public function mergeWith($style)
6120         {
6121                 parent::mergeWith($style);
6122                 if($style instanceof TTableStyle)
6123                 {
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;
6136                 }
6137         }
6138         public function addAttributesToRender($writer)
6139         {
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())
6151                 {
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;
6155                 }
6156                 parent::addAttributesToRender($writer);
6157         }
6158         public function getBackImageUrl()
6159         {
6160                 return $this->_backImageUrl===null?'':$this->_backImageUrl;
6161         }
6162         public function setBackImageUrl($value)
6163         {
6164                 $this->_backImageUrl=$value;
6165         }
6166         public function getHorizontalAlign()
6167         {
6168                 return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6169         }
6170         public function setHorizontalAlign($value)
6171         {
6172                 $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6173         }
6174         public function getCellPadding()
6175         {
6176                 return $this->_cellPadding===null?-1:$this->_cellPadding;
6177         }
6178         public function setCellPadding($value)
6179         {
6180                 if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
6181                         throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
6182         }
6183         public function getCellSpacing()
6184         {
6185                 return $this->_cellSpacing===null?-1:$this->_cellSpacing;
6186         }
6187         public function setCellSpacing($value)
6188         {
6189                 if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
6190                         throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
6191         }
6192         public function getGridLines()
6193         {
6194                 return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
6195         }
6196         public function setGridLines($value)
6197         {
6198                 $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
6199         }
6200         public function getBorderCollapse()
6201         {
6202                 return $this->_borderCollapse===null?false:$this->_borderCollapse;
6203         }
6204         public function setBorderCollapse($value)
6205         {
6206                 $this->_borderCollapse=TPropertyValue::ensureBoolean($value);
6207         }
6208 }
6209 class TTableItemStyle extends TStyle
6210 {
6211         private $_horizontalAlign=null;
6212         private $_verticalAlign=null;
6213         private $_wrap=null;
6214         protected function _getZappableSleepProps(&$exprops)
6215         {
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";
6223         }
6224         public function reset()
6225         {
6226                 parent::reset();
6227                 $this->_verticalAlign=null;
6228                 $this->_horizontalAlign=null;
6229                 $this->_wrap=null;
6230         }
6231         public function copyFrom($style)
6232         {
6233                 parent::copyFrom($style);
6234                 if($style instanceof TTableItemStyle)
6235                 {
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;
6242                 }
6243         }
6244         public function mergeWith($style)
6245         {
6246                 parent::mergeWith($style);
6247                 if($style instanceof TTableItemStyle)
6248                 {
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;
6255                 }
6256         }
6257         public function addAttributesToRender($writer)
6258         {
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);
6266         }
6267         public function getHorizontalAlign()
6268         {
6269                 return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6270         }
6271         public function setHorizontalAlign($value)
6272         {
6273                 $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6274         }
6275         public function getVerticalAlign()
6276         {
6277                 return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
6278         }
6279         public function setVerticalAlign($value)
6280         {
6281                 $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
6282         }
6283         public function getWrap()
6284         {
6285                 return $this->_wrap===null?true:$this->_wrap;
6286         }
6287         public function setWrap($value)
6288         {
6289                 $this->_wrap=TPropertyValue::ensureBoolean($value);
6290         }
6291 }
6292 class THorizontalAlign extends TEnumerable
6293 {
6294         const NotSet='NotSet';
6295         const Left='Left';
6296         const Right='Right';
6297         const Center='Center';
6298         const Justify='Justify';
6299 }
6300 class TVerticalAlign extends TEnumerable
6301 {
6302         const NotSet='NotSet';
6303         const Top='Top';
6304         const Bottom='Bottom';
6305         const Middle='Middle';
6306 }
6307 class TTableGridLines extends TEnumerable
6308 {
6309         const None='None';
6310         const Horizontal='Horizontal';
6311         const Vertical='Vertical';
6312         const Both='Both';
6313 }
6314 class TWebControlAdapter extends TControlAdapter
6315 {
6316         public function render($writer)
6317         {
6318                 $this->renderBeginTag($writer);
6319                 $this->renderContents($writer);
6320                 $this->renderEndTag($writer);
6321         }
6322         public function renderBeginTag($writer)
6323         {
6324                 $this->getControl()->renderBeginTag($writer);
6325         }
6326         public function renderContents($writer)
6327         {
6328                 $this->getControl()->renderContents($writer);
6329         }
6330         public function renderEndTag($writer)
6331         {
6332                 $this->getControl()->renderEndTag($writer);
6333         }
6334 }
6335 class TWebControlDecorator extends TComponent {
6336         private $_internalonly;
6337         private $_usestate = false;
6338         private $_control;
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;
6352         }
6353         public function getUseState()
6354         {
6355                 return $this->_usestate;
6356         }
6357         public function setUseState($value)
6358         {
6359                 $this->_usestate = TPropertyValue::ensureBoolean($value);
6360         }
6361         public function getPreTagText() {
6362                 return $this->_pretagtext;
6363         }
6364         public function setPreTagText($value) {
6365                 if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6366                         $this->_pretagtext = TPropertyValue::ensureString($value);
6367         }
6368         public function getPreContentsText() {
6369                 return $this->_precontentstext;
6370         }
6371         public function setPreContentsText($value) {
6372                 if(!$this->_control->getIsSkinApplied())
6373                         $this->_precontentstext = TPropertyValue::ensureString($value);
6374         }
6375         public function getPostContentsText() {
6376                 return $this->_postcontentstext;
6377         }
6378         public function setPostContentsText($value) {
6379                 if(!$this->_control->getIsSkinApplied())
6380                         $this->_postcontentstext = TPropertyValue::ensureString($value);
6381         }
6382         public function getPostTagText() {
6383                 return $this->_posttagtext;
6384         }
6385         public function setPostTagText($value) {
6386                 if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6387                         $this->_posttagtext = TPropertyValue::ensureString($value);
6388         }
6389         public function getPreTagTemplate() {
6390                 return $this->_pretagtemplate;
6391         }
6392         public function setPreTagTemplate($value) {
6393                 if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6394                         $this->_pretagtemplate = $value;
6395         }
6396         public function getPreContentsTemplate() {
6397                 return $this->_precontentstemplate;
6398         }
6399         public function setPreContentsTemplate($value) {
6400                 if(!$this->_control->getIsSkinApplied())
6401                         $this->_precontentstemplate = $value;
6402         }
6403         public function getPostContentsTemplate() {
6404                 return $this->_postcontentstemplate;
6405         }
6406         public function setPostContentsTemplate($value) {
6407                 if(!$this->_control->getIsSkinApplied())
6408                         $this->_postcontentstemplate = $value;
6409         }
6410         public function getPostTagTemplate() {
6411                 return $this->_posttagtemplate;
6412         }
6413         public function setPostTagTemplate($value) {
6414                 if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6415                         $this->_posttagtemplate = $value;
6416         }
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();
6423                         else
6424                                 $this->_control->getPage()->onSaveStateComplete[] = array($this, 'ensureTemplateDecoration');
6425                 }
6426         }
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())
6436                 {
6437                         $precontents = Prado::createComponent('TCompositeControl');
6438                         $this->getPreContentsTemplate()->instantiateIn($precontents);
6439                         $control->getControls()->insertAt(0, $precontents);
6440                 }
6441                 if($this->getPostContentsTemplate())
6442                 {
6443                         $postcontents = Prado::createComponent('TCompositeControl');
6444                         $this->getPostContentsTemplate()->instantiateIn($postcontents);
6445                         $control->getControls()->add($postcontents);
6446                 }
6447                 if(!$outercontrol->getParent())
6448                         return $this->_addedTemplateDecoration;
6449                 if($this->getPreTagTemplate())
6450                 {
6451                         $pretag = Prado::createComponent('TCompositeControl');
6452                         $this->getPreTagTemplate()->instantiateIn($pretag);
6453                         $outercontrol->getParent()->getControls()->insertBefore($outercontrol, $pretag);
6454                 }
6455                 if($this->getPostTagTemplate())
6456                 {
6457                         $posttag = Prado::createComponent('TCompositeControl');
6458                         $this->getPostTagTemplate()->instantiateIn($posttag);
6459                         $outercontrol->getParent()->getControls()->insertAfter($outercontrol, $posttag);
6460                 }
6461                 return true;
6462         }
6463         public function renderPreTagText($writer) {
6464                 $writer->write($this->getPreTagText());
6465         }
6466         public function renderPreContentsText($writer) {
6467                 $writer->write($this->getPreContentsText());
6468         }
6469         public function renderPostContentsText($writer) {
6470                 $writer->write($this->getPostContentsText());
6471         }
6472         public function renderPostTagText($writer) {
6473                 $writer->write($this->getPostTagText());
6474         }
6475 }
6476 class TWebControl extends TControl implements IStyleable
6477 {
6478         private $_ensureid=false;
6479         protected $_decorator;
6480         public function setEnsureId($value)
6481         {
6482                 $this->_ensureid |= TPropertyValue::ensureBoolean($value);
6483         }
6484         public function getEnsureId()
6485         {
6486                 return $this->_ensureid;
6487         }
6488         public function getDecorator($create=true)
6489         {
6490                 if($create && !$this->_decorator)
6491                         $this->_decorator = Prado::createComponent('TWebControlDecorator', $this);
6492                 return $this->_decorator;
6493         }
6494         public function copyBaseAttributes(TWebControl $control)
6495         {
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());
6503         }
6504         public function getAccessKey()
6505         {
6506                 return $this->getViewState('AccessKey','');
6507         }
6508         public function setAccessKey($value)
6509         {
6510                 if(strlen($value)>1)
6511                         throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
6512                 $this->setViewState('AccessKey',$value,'');
6513         }
6514         public function getBackColor()
6515         {
6516                 if($style=$this->getViewState('Style',null))
6517                         return $style->getBackColor();
6518                 else
6519                         return '';
6520         }
6521         public function setBackColor($value)
6522         {
6523                 $this->getStyle()->setBackColor($value);
6524         }
6525         public function getBorderColor()
6526         {
6527                 if($style=$this->getViewState('Style',null))
6528                         return $style->getBorderColor();
6529                 else
6530                         return '';
6531         }
6532         public function setBorderColor($value)
6533         {
6534                 $this->getStyle()->setBorderColor($value);
6535         }
6536         public function getBorderStyle()
6537         {
6538                 if($style=$this->getViewState('Style',null))
6539                         return $style->getBorderStyle();
6540                 else
6541                         return '';
6542         }
6543         public function setBorderStyle($value)
6544         {
6545                 $this->getStyle()->setBorderStyle($value);
6546         }
6547         public function getBorderWidth()
6548         {
6549                 if($style=$this->getViewState('Style',null))
6550                         return $style->getBorderWidth();
6551                 else
6552                         return '';
6553         }
6554         public function setBorderWidth($value)
6555         {
6556                 $this->getStyle()->setBorderWidth($value);
6557         }
6558         public function getFont()
6559         {
6560                 return $this->getStyle()->getFont();
6561         }
6562         public function getForeColor()
6563         {
6564                 if($style=$this->getViewState('Style',null))
6565                         return $style->getForeColor();
6566                 else
6567                         return '';
6568         }
6569         public function setForeColor($value)
6570         {
6571                 $this->getStyle()->setForeColor($value);
6572         }
6573         public function getHeight()
6574         {
6575                 if($style=$this->getViewState('Style',null))
6576                         return $style->getHeight();
6577                 else
6578                         return '';
6579         }
6580         public function setDisplay($value)
6581         {
6582                 $this->getStyle()->setDisplayStyle($value);
6583         }
6584         public function getDisplay()
6585         {
6586                 return $this->getStyle()->getDisplayStyle();
6587         }
6588         public function setCssClass($value)
6589         {
6590                 $this->getStyle()->setCssClass($value);
6591         }
6592         public function getCssClass()
6593         {
6594                 if($style=$this->getViewState('Style',null))
6595                         return $style->getCssClass();
6596                 else
6597                         return '';
6598         }
6599         public function setHeight($value)
6600         {
6601                 $this->getStyle()->setHeight($value);
6602         }
6603         public function getHasStyle()
6604         {
6605                 return $this->getViewState('Style',null)!==null;
6606         }
6607         protected function createStyle()
6608         {
6609                 return new TStyle;
6610         }
6611         public function getStyle()
6612         {
6613                 if($style=$this->getViewState('Style',null))
6614                         return $style;
6615                 else
6616                 {
6617                         $style=$this->createStyle();
6618                         $this->setViewState('Style',$style,null);
6619                         return $style;
6620                 }
6621         }
6622         public function setStyle($value)
6623         {
6624                 if(is_string($value))
6625                         $this->getStyle()->setCustomStyle($value);
6626                 else
6627                         throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
6628         }
6629         public function clearStyle()
6630         {
6631                 $this->clearViewState('Style');
6632         }
6633         public function getTabIndex()
6634         {
6635                 return $this->getViewState('TabIndex',0);
6636         }
6637         public function setTabIndex($value)
6638         {
6639                 $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
6640         }
6641         protected function getTagName()
6642         {
6643                 return 'span';
6644         }
6645         public function getToolTip()
6646         {
6647                 return $this->getViewState('ToolTip','');
6648         }
6649         public function setToolTip($value)
6650         {
6651                 $this->setViewState('ToolTip',$value,'');
6652         }
6653         public function getWidth()
6654         {
6655                 if($style=$this->getViewState('Style',null))
6656                         return $style->getWidth();
6657                 else
6658                         return '';
6659         }
6660         public function setWidth($value)
6661         {
6662                 $this->getStyle()->setWidth($value);
6663         }
6664         public function onPreRender($param) {
6665                 if($decorator = $this->getDecorator(false))
6666                         $decorator->instantiate();
6667                 parent::onPreRender($param);
6668         }
6669         protected function addAttributesToRender($writer)
6670         {
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())
6684                 {
6685                         foreach($this->getAttributes() as $name=>$value)
6686                                 $writer->addAttribute($name,$value);
6687                 }
6688         }
6689         public function render($writer)
6690         {
6691                 $this->renderBeginTag($writer);
6692                 $this->renderContents($writer);
6693                 $this->renderEndTag($writer);
6694         }
6695         public function renderBeginTag($writer)
6696         {
6697                 if($decorator = $this->getDecorator(false)) {
6698                         $decorator->renderPreTagText($writer);
6699                         $this->addAttributesToRender($writer);
6700                         $writer->renderBeginTag($this->getTagName());
6701                         $decorator->renderPreContentsText($writer);
6702                 } else {
6703                         $this->addAttributesToRender($writer);
6704                         $writer->renderBeginTag($this->getTagName());
6705                 }
6706         }
6707         public function renderContents($writer)
6708         {
6709                 parent::renderChildren($writer);
6710         }
6711         public function renderEndTag($writer)
6712         {
6713                 if($decorator = $this->getDecorator(false)) {
6714                         $decorator->renderPostContentsText($writer);
6715                         $writer->renderEndTag();
6716                         $decorator->renderPostTagText($writer);
6717                 } else
6718                         $writer->renderEndTag($writer);
6719         }
6720 }
6721 class TCompositeControl extends TControl implements INamingContainer
6722 {
6723         protected function initRecursive($namingContainer=null)
6724         {
6725                 $this->ensureChildControls();
6726                 parent::initRecursive($namingContainer);
6727         }
6728 }
6729 class TTemplateControl extends TCompositeControl
6730 {
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()
6739         {
6740                 if($this->_localTemplate===null)
6741                 {
6742                         $class=get_class($this);
6743                         if(!isset(self::$_template[$class]))
6744                                 self::$_template[$class]=$this->loadTemplate();
6745                         return self::$_template[$class];
6746                 }
6747                 else
6748                         return $this->_localTemplate;
6749         }
6750         public function setTemplate($value)
6751         {
6752                 $this->_localTemplate=$value;
6753         }
6754         public function getIsSourceTemplateControl()
6755         {
6756                 if(($template=$this->getTemplate())!==null)
6757                         return $template->getIsSourceTemplate();
6758                 else
6759                         return false;
6760         }
6761         public function getTemplateDirectory()
6762         {
6763                 if(($template=$this->getTemplate())!==null)
6764                         return $template->getContextPath();
6765                 else
6766                         return '';
6767         }
6768         protected function loadTemplate()
6769         {
6770                 $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
6771                 return $template;
6772         }
6773         public function createChildControls()
6774         {
6775                 if($tpl=$this->getTemplate())
6776                 {
6777                         foreach($tpl->getDirective() as $name=>$value)
6778                         {
6779                                 if(is_string($value))
6780                                         $this->setSubProperty($name,$value);
6781                                 else
6782                                         throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
6783                         }
6784                         $tpl->instantiateIn($this);
6785                 }
6786         }
6787         public function registerContent($id,TContent $object)
6788         {
6789                 if(isset($this->_contents[$id]))
6790                         throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
6791                 else
6792                         $this->_contents[$id]=$object;
6793         }
6794         public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
6795         {
6796                 if(isset($this->_placeholders[$id]))
6797                         throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
6798                 else
6799                         $this->_placeholders[$id]=$object;
6800         }
6801         public function getMasterClass()
6802         {
6803                 return $this->_masterClass;
6804         }
6805         public function setMasterClass($value)
6806         {
6807                 $this->_masterClass=$value;
6808         }
6809         public function getMaster()
6810         {
6811                 return $this->_master;
6812         }
6813         public function injectContent($id,$content)
6814         {
6815                 if(isset($this->_placeholders[$id]))
6816                 {
6817                         $placeholder=$this->_placeholders[$id];
6818                         $controls=$placeholder->getParent()->getControls();
6819                         $loc=$controls->remove($placeholder);
6820                         $controls->insertAt($loc,$content);
6821                 }
6822                 else
6823                         throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
6824         }
6825         protected function initRecursive($namingContainer=null)
6826         {
6827                 $this->ensureChildControls();
6828                 if($this->_masterClass!=='')
6829                 {
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);
6839                 }
6840                 else if(!empty($this->_contents))
6841                         throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
6842                 parent::initRecursive($namingContainer);
6843         }
6844         public function tryToUpdateView($arObj, $throwExceptions = false)
6845         {
6846                 $objAttrs = get_class_vars(get_class($arObj));
6847                 foreach (array_keys($objAttrs) as $key)
6848                 {
6849                         try
6850                         {
6851                                 if ($key != "RELATIONS")
6852                                 {
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};
6860                                 }
6861                                 else
6862                                 {
6863                                         foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
6864                                         {
6865                                                 $relControl = $this->{$relKey};
6866                                                 switch ($relValues[0])
6867                                                 {
6868                                                         case TActiveRecord::BELONGS_TO:
6869                                                         case TActiveRecord::HAS_ONE:
6870                                                                 $relControl->Text = $arObj->{$relKey};
6871                                                                 break;
6872                                                         case TActiveRecord::HAS_MANY:
6873                                                                 if ($relControl instanceof TListControl)
6874                                                                 {
6875                                                                         $relControl->DataSource = $arObj->{$relKey};
6876                                                                         $relControl->dataBind();
6877                                                                 }
6878                                                                 break;
6879                                                 }
6880                                         }
6881                                         break;
6882                                 }
6883                         } 
6884                         catch (Exception $ex)
6885                         {
6886                                 if ($throwExceptions)
6887                                         throw $ex;
6888                         }
6889                 }
6890         }
6891         public function tryToUpdateAR($arObj, $throwExceptions = false)
6892         {
6893                 $objAttrs = get_class_vars(get_class($arObj));
6894                 foreach (array_keys($objAttrs) as $key)
6895                 {
6896                         try
6897                         {
6898                                 if ($key == "RELATIONS")
6899                                         break;
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;
6907                         } 
6908                         catch (Exception $ex)
6909                         {
6910                                 if ($throwExceptions)
6911                                         throw $ex;
6912                         }
6913                 }
6914         }
6915 }
6916 class TForm extends TControl
6917 {
6918         public function onInit($param)
6919         {
6920                 parent::onInit($param);
6921                 $this->getPage()->setForm($this);
6922         }
6923         protected function addAttributesToRender($writer)
6924         {
6925                 $writer->addAttribute('id',$this->getClientID());
6926                 $writer->addAttribute('method',$this->getMethod());
6927                 $uri=$this->getRequest()->getRequestURI();
6928                 $writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$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())!=='')
6935                 {
6936                         if(($button=$this->findControl($butt))!==null)
6937                                 $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
6938                         else
6939                                 throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
6940                 }
6941         }
6942         public function render($writer)
6943         {
6944                 $page=$this->getPage();
6945                 $this->addAttributesToRender($writer);
6946                 $writer->renderBeginTag('form');
6947                 $cs=$page->getClientScript();
6948                 if($page->getClientSupportsJavaScript())
6949                 {
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);
6959                 }
6960                 else
6961                 {
6962                         $cs->renderHiddenFieldsBegin($writer);
6963                         $page->beginFormRender($writer);
6964                         $this->renderChildren($writer);
6965                         $page->endFormRender($writer);
6966                         $cs->renderHiddenFieldsEnd($writer);
6967                 }
6968                 $writer->renderEndTag();
6969         }
6970         public function getDefaultButton()
6971         {
6972                 return $this->getViewState('DefaultButton','');
6973         }
6974         public function setDefaultButton($value)
6975         {
6976                 $this->setViewState('DefaultButton',$value,'');
6977         }
6978         public function getMethod()
6979         {
6980                 return $this->getViewState('Method','post');
6981         }
6982         public function setMethod($value)
6983         {
6984                 $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
6985         }
6986         public function getEnctype()
6987         {
6988                 return $this->getViewState('Enctype','');
6989         }
6990         public function setEnctype($value)
6991         {
6992                 $this->setViewState('Enctype',$value,'');
6993         }
6994         public function getName()
6995         {
6996                 return $this->getUniqueID();
6997         }
6998 }
6999 class TClientScriptManager extends TApplicationComponent
7000 {
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';
7004         private $_page;
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)
7024         {
7025                 $this->_page=$owner;
7026         }
7027         public function getRequiresHead()
7028         {
7029                 return count($this->_styleSheetFiles) || count($this->_styleSheets)
7030                         || count($this->_headScriptFiles) || count($this->_headScripts);
7031         }
7032         public static function getPradoPackages()
7033         {
7034                 return self::$_pradoPackages;
7035         }
7036         public static function getPradoScripts()
7037         {
7038                 return self::$_pradoScripts;
7039         }
7040         public function registerPradoScript($name)
7041         {
7042                 $this->registerPradoScriptInternal($name);
7043                 $params=func_get_args();
7044                 $this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
7045         }
7046         protected function registerPradoScriptInternal($name)
7047         {
7048                                 if(!isset($this->_registeredPradoScripts[$name]))
7049                 {
7050                         if(self::$_pradoScripts === null)
7051                         {
7052                                 $packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::PACKAGES_FILE;
7053                                 list($packages,$deps)= include($packageFile);
7054                                 self::$_pradoScripts = $deps;
7055                                 self::$_pradoPackages = $packages;
7056                         }
7057                         if (isset(self::$_pradoScripts[$name]))
7058                                 $this->_registeredPradoScripts[$name]=true;
7059                         else
7060                                 throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
7061                         if(($packages=array_keys($this->_registeredPradoScripts))!==array())
7062                         {
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)
7068                                 {
7069                                         foreach (self::$_pradoScripts[$p] as $dep)
7070                                         {
7071                                                 foreach (self::$_pradoPackages[$dep] as $script)
7072                                                 if (!isset($this->_expandedPradoScripts[$script]))
7073                                                 {
7074                                                         $this->_expandedPradoScripts[$script] = true;
7075                                                         if($isDebug)
7076                                                         {
7077                                                                 if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
7078                                                                         $packagesUrl[]=$url;
7079                                                         } else {
7080                                                                 if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))
7081                                                                 {
7082                                                                         if(!is_file($filePath=$path.'/min/'.$script))
7083                                                                         {
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);
7089                                                                         }
7090                                                                         $packagesUrl[]=$url;
7091                                                                 }
7092                                                         }
7093                                                 }
7094                                         }
7095                                 }
7096                                 foreach($packagesUrl as $url)
7097                                         $this->registerScriptFile($url,$url);
7098                         }
7099                 }
7100         }
7101         public function getPradoScriptAssetUrl()
7102         {
7103                 $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7104                 $assets = Prado::getApplication()->getAssetManager();
7105                 return $assets->getPublishedUrl($base);
7106         }
7107         public function getScriptUrls()
7108         {
7109                 $scripts = array_values($this->_headScriptFiles);
7110                 $scripts = array_merge($scripts, array_values($this->_scriptFiles));
7111                 $scripts = array_unique($scripts);
7112                 return $scripts;
7113         }
7114         protected function getPackagePathUrl($base)
7115         {
7116                 $assets = Prado::getApplication()->getAssetManager();
7117                 if(strpos($base, $assets->getBaseUrl())===false)
7118                 {
7119                         if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
7120                                 $base = $dir;
7121                         }
7122                         return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
7123                 }
7124                 else
7125                 {
7126                         return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
7127                 }
7128         }
7129         public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
7130         {
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})";
7139         }
7140         public function registerCallbackControl($class, $options)
7141         {
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);
7148         }
7149         public function registerPostBackControl($class,$options)
7150         {
7151                 if($class === null) {
7152                         return;
7153                 }
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);
7162         }
7163         public function registerDefaultButton($panel, $button)
7164         {
7165                 $panelID=is_string($panel)?$panel:$panel->getUniqueID();
7166                 if(is_string($button))
7167                         $buttonID=$button;
7168                 else
7169                 {
7170                         $button->setIsDefaultButton(true);
7171                         $buttonID=$button->getUniqueID();
7172                 }
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);
7179         }
7180         protected function getDefaultButtonOptions($panelID, $buttonID)
7181         {
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';
7187                 return $options;
7188         }
7189         public function registerFocusControl($target)
7190         {
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);
7197         }
7198         public function registerPradoStyle($name)
7199         {
7200                 $this->registerPradoStyleInternal($name);
7201                 $params=func_get_args();
7202                 $this->_page->registerCachingAction('Page.ClientScript','registerPradoStyle',$params);
7203         }
7204         protected function registerPradoStyleInternal($name)
7205         {
7206                                 if(!isset($this->_registeredPradoStyles[$name]))
7207                 {
7208                         $base = $this->getPradoScriptAssetUrl();
7209                         if(self::$_pradoStyles === null)
7210                         {
7211                                 $packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::CSS_PACKAGES_FILE;
7212                                 list($packages,$deps)= include($packageFile);
7213                                 self::$_pradoStyles = $deps;
7214                                 self::$_pradoStylePackages = $packages;
7215                         }
7216                         if (isset(self::$_pradoStyles[$name]))
7217                                 $this->_registeredPradoStyles[$name]=true;
7218                         else
7219                                 throw new TInvalidOperationException('csmanager_pradostyle_invalid',$name);
7220                         if(($packages=array_keys($this->_registeredPradoStyles))!==array())
7221                         {
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)
7227                                 {
7228                                         foreach (self::$_pradoStyles[$p] as $dep)
7229                                         {
7230                                                 foreach (self::$_pradoStylePackages[$dep] as $style)
7231                                                 if (!isset($this->_expandedPradoStyles[$style]))
7232                                                 {
7233                                                         $this->_expandedPradoStyles[$style] = true;
7234                                                                                                                 if (!in_array($url=$baseUrl.'/'.$style,$packagesUrl))
7235                                                                 $packagesUrl[]=$url;
7236                                                 }
7237                                         }
7238                                 }
7239                                 foreach($packagesUrl as $url)
7240                                         $this->registerStyleSheetFile($url,$url);
7241                         }
7242                 }
7243         }
7244         public function registerStyleSheetFile($key,$url,$media='')
7245         {
7246                 if($media==='')
7247                         $this->_styleSheetFiles[$key]=$url;
7248                 else
7249                         $this->_styleSheetFiles[$key]=array($url,$media);
7250                 $params=func_get_args();
7251                 $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
7252         }
7253         public function registerStyleSheet($key,$css,$media='')
7254         {
7255                 $this->_styleSheets[$key]=$css;
7256                 $params=func_get_args();
7257                 $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
7258         }
7259         public function getStyleSheetUrls()
7260         {
7261                 $stylesheets = array_values(
7262                         array_map(function($e) {
7263                                 return is_array($e) ? $e[0] : $e;
7264                         }, $this->_styleSheetFiles)
7265                 );
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;
7271         }
7272         public function getStyleSheetCodes()
7273         {
7274                 return array_unique(array_values($this->_styleSheets));
7275         }
7276         public function registerHeadScriptFile($key,$url)
7277         {
7278                 $this->checkIfNotInRender();
7279                 $this->_headScriptFiles[$key]=$url;
7280                 $params=func_get_args();
7281                 $this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
7282         }
7283         public function registerHeadScript($key,$script)
7284         {
7285                 $this->checkIfNotInRender();
7286                 $this->_headScripts[$key]=$script;
7287                 $params=func_get_args();
7288                 $this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
7289         }
7290         public function registerScriptFile($key, $url)
7291         {
7292                 $this->_scriptFiles[$key]=$url;
7293                 $params=func_get_args();
7294                 $this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
7295         }
7296         public function registerBeginScript($key,$script)
7297         {
7298                 $this->checkIfNotInRender();
7299                 $this->_beginScripts[$key]=$script;
7300                 $params=func_get_args();
7301                 $this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
7302         }
7303         public function registerEndScript($key,$script)
7304         {
7305                 $this->_endScripts[$key]=$script;
7306                 $params=func_get_args();
7307                 $this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
7308         }
7309         public function registerHiddenField($name,$value)
7310         {
7311                 $this->_hiddenFields[$name]=$value;
7312                 $params=func_get_args();
7313                 $this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
7314         }
7315         public function isStyleSheetFileRegistered($key)
7316         {
7317                 return isset($this->_styleSheetFiles[$key]);
7318         }
7319         public function isStyleSheetRegistered($key)
7320         {
7321                 return isset($this->_styleSheets[$key]);
7322         }
7323         public function isHeadScriptFileRegistered($key)
7324         {
7325                 return isset($this->_headScriptFiles[$key]);
7326         }
7327         public function isHeadScriptRegistered($key)
7328         {
7329                 return isset($this->_headScripts[$key]);
7330         }
7331         public function isScriptFileRegistered($key)
7332         {
7333                 return isset($this->_scriptFiles[$key]);
7334         }
7335         public function isBeginScriptRegistered($key)
7336         {
7337                 return isset($this->_beginScripts[$key]);
7338         }
7339         public function isEndScriptRegistered($key)
7340         {
7341                 return isset($this->_endScripts[$key]);
7342         }
7343         public function hasEndScripts()
7344         {
7345                 return count($this->_endScripts) > 0;
7346         }
7347         public function hasBeginScripts()
7348         {
7349                 return count($this->_beginScripts) > 0;
7350         }
7351         public function isHiddenFieldRegistered($key)
7352         {
7353                 return isset($this->_hiddenFields[$key]);
7354         }
7355         public function renderStyleSheetFiles($writer)
7356         {
7357                 $str='';
7358                 foreach($this->_styleSheetFiles as $url)
7359                 {
7360                         if(is_array($url))
7361                                 $str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
7362                         else
7363                                 $str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
7364                 }
7365                 $writer->write($str);
7366         }
7367         public function renderStyleSheets($writer)
7368         {
7369                 if(count($this->_styleSheets))
7370                         $writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
7371         }
7372         public function renderHeadScriptFiles($writer)
7373         {
7374                 $this->renderScriptFiles($writer,$this->_headScriptFiles);
7375         }
7376         public function renderHeadScripts($writer)
7377         {
7378                 $writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
7379         }
7380         public function renderScriptFilesBegin($writer)
7381         {
7382                 $this->renderAllPendingScriptFiles($writer);
7383         }
7384         public function renderScriptFilesEnd($writer)
7385         {
7386                 $this->renderAllPendingScriptFiles($writer);
7387         }
7388         public function markScriptFileAsRendered($url)
7389         {
7390                 $this->_renderedScriptFiles[$url] = $url;
7391                 $params=func_get_args();
7392                 $this->_page->registerCachingAction('Page.ClientScript','markScriptFileAsRendered',$params);
7393         }
7394         protected function renderScriptFiles($writer, Array $scripts)
7395         {
7396                 foreach($scripts as $script)
7397                 {
7398                         $writer->write(TJavaScript::renderScriptFile($script));
7399                         $this->markScriptFileAsRendered($script);
7400                 }
7401         }
7402         protected function getRenderedScriptFiles()
7403         {
7404                 return $this->_renderedScriptFiles;
7405         }
7406         public function renderAllPendingScriptFiles($writer)
7407         {
7408                 if(!empty($this->_scriptFiles))
7409                 {
7410                         $addedScripts = array_diff($this->_scriptFiles,$this->getRenderedScriptFiles());
7411                         $this->renderScriptFiles($writer,$addedScripts);
7412                 }
7413         }
7414         public function renderBeginScripts($writer)
7415         {
7416                 $writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
7417         }
7418         public function renderEndScripts($writer)
7419         {
7420                 $writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
7421         }
7422         public function renderBeginScriptsCallback($writer)
7423         {
7424                 $writer->write(TJavaScript::renderScriptBlocksCallback($this->_beginScripts));
7425         }
7426         public function renderEndScriptsCallback($writer)
7427         {
7428                 $writer->write(TJavaScript::renderScriptBlocksCallback($this->_endScripts));
7429         }
7430         public function renderHiddenFieldsBegin($writer)
7431         {
7432                 $this->renderHiddenFieldsInt($writer,true);
7433         }
7434         public function renderHiddenFieldsEnd($writer)
7435         {
7436                 $this->renderHiddenFieldsInt($writer,false);
7437         }
7438         public function flushScriptFiles($writer, $control=null)
7439         {
7440                 if(!$this->_page->getIsCallback())
7441                 {
7442                         $this->_page->ensureRenderInForm($control);
7443                         $this->renderAllPendingScriptFiles($writer);
7444                 }
7445         }
7446         protected function renderHiddenFieldsInt($writer, $initial)
7447         {
7448                 if ($initial) $this->_renderedHiddenFields = array();
7449                 $str='';
7450                 foreach($this->_hiddenFields as $name=>$value)
7451                 {
7452                         if (in_array($name,$this->_renderedHiddenFields)) continue;
7453                         $id=strtr($name,':','_');
7454                         if(is_array($value))
7455                         {
7456                                 foreach($value as $v)
7457                                         $str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7458                         }
7459                         else
7460                         {
7461                                 $str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7462                         }
7463                         $this->_renderedHiddenFields[] = $name;
7464                 }
7465                 if($str!=='')
7466                         $writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
7467         }
7468         public function getHiddenFields()
7469         {
7470                 return $this->_hiddenFields;
7471         }
7472         protected function checkIfNotInRender()
7473         {
7474                 if ($form = $this->_page->InFormRender)
7475                         throw new Exception('Operation invalid when page is already rendering');
7476         }
7477 }
7478 abstract class TClientSideOptions extends TComponent
7479 {
7480         private $_options;
7481         protected function setFunction($name, $code)
7482         {
7483                 if(!TJavaScript::isJsLiteral($code))
7484                         $code = TJavaScript::quoteJsLiteral($this->ensureFunction($code));
7485                 $this->setOption($name, $code);
7486         }
7487         protected function getOption($name)
7488         {
7489                 if ($this->_options)
7490                         return $this->_options->itemAt($name);
7491                 else
7492                         return null;
7493         }
7494         protected function setOption($name, $value)
7495         {
7496                 $this->getOptions()->add($name, $value);
7497         }
7498         public function getOptions()
7499         {
7500                 if (!$this->_options)
7501                         $this->_options = Prado::createComponent('System.Collections.TMap');
7502                 return $this->_options;
7503         }
7504         protected function ensureFunction($javascript)
7505         {
7506                 return "function(sender, parameter){ {$javascript} }";
7507         }
7508 }
7509 class TPage extends TTemplateControl
7510 {
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
7524         );
7525         private $_form;
7526         private $_head;
7527         private $_validators=array();
7528         private $_validated=false;
7529         private $_theme;
7530         private $_title;
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;
7542         private $_focus;
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;
7553         private $_writer;
7554         public function __construct()
7555         {
7556                 $this->setPage($this);
7557         }
7558         public function run($writer)
7559         {
7560                 $this->_writer = $writer;
7561                 $this->determinePostBackMode();
7562                 if($this->getIsPostBack())
7563                 {
7564                         if($this->getIsCallback())
7565                                 $this->processCallbackRequest($writer);
7566                         else
7567                                 $this->processPostBackRequest($writer);
7568                 }
7569                 else
7570                         $this->processNormalRequest($writer);
7571                 $this->_writer = null;
7572         }
7573         protected function processNormalRequest($writer)
7574         {
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();
7587         }
7588         protected function processPostBackRequest($writer)
7589         {
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();
7608         }
7609         protected static function decodeUTF8($data, $enc)
7610         {
7611                 if(is_array($data))
7612                 {
7613                         foreach($data as $k=>$v)
7614                                 $data[$k]=self::decodeUTF8($v, $enc);
7615                         return $data;
7616                 } elseif(is_string($data)) {
7617                         return iconv('UTF-8',$enc.'//IGNORE',$data);
7618                 } else {
7619                         return $data;
7620                 }
7621         }
7622         protected function processCallbackRequest($writer)
7623         {
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();
7652         }
7653         public function getCallbackClient()
7654         {
7655                 if($this->getAdapter() !== null)
7656                         return $this->getAdapter()->getCallbackClientHandler();
7657                 else
7658                         return new TCallbackClientScript();
7659         }
7660         public function setCallbackClient($client)
7661         {
7662                 $this->getAdapter()->setCallbackClientHandler($client);
7663         }
7664         public function getCallbackEventTarget()
7665         {
7666                 return $this->getAdapter()->getCallbackEventTarget();
7667         }
7668         public function setCallbackEventTarget(TControl $control)
7669         {
7670                 $this->getAdapter()->setCallbackEventTarget($control);
7671         }
7672         public function getCallbackEventParameter()
7673         {
7674                 return $this->getAdapter()->getCallbackEventParameter();
7675         }
7676         public function setCallbackEventParameter($value)
7677         {
7678                 $this->getAdapter()->setCallbackEventParameter($value);
7679         }
7680         public function getForm()
7681         {
7682                 return $this->_form;
7683         }
7684         public function setForm(TForm $form)
7685         {
7686                 if($this->_form===null)
7687                         $this->_form=$form;
7688                 else
7689                         throw new TInvalidOperationException('page_form_duplicated');
7690         }
7691         public function getValidators($validationGroup=null)
7692         {
7693                 if(!$this->_validators)
7694                         $this->_validators=new TList;
7695                 if(empty($validationGroup) === true)
7696                         return $this->_validators;
7697                 else
7698                 {
7699                         $list=new TList;
7700                         foreach($this->_validators as $validator)
7701                                 if($validator->getValidationGroup()===$validationGroup)
7702                                         $list->add($validator);
7703                         return $list;
7704                 }
7705         }
7706         public function validate($validationGroup=null)
7707         {
7708                 $this->_validated=true;
7709                 if($this->_validators && $this->_validators->getCount())
7710                 {
7711                         if($validationGroup===null)
7712                         {
7713                                 foreach($this->_validators as $validator)
7714                                         $validator->validate();
7715                         }
7716                         else
7717                         {
7718                                 foreach($this->_validators as $validator)
7719                                 {
7720                                         if($validator->getValidationGroup()===$validationGroup)
7721                                                 $validator->validate();
7722                                 }
7723                         }
7724                 }
7725         }
7726         public function getIsValid()
7727         {
7728                 if($this->_validated)
7729                 {
7730                         if($this->_validators && $this->_validators->getCount())
7731                         {
7732                                 foreach($this->_validators as $validator)
7733                                         if(!$validator->getIsValid())
7734                                                 return false;
7735                         }
7736                         return true;
7737                 }
7738                 else
7739                         throw new TInvalidOperationException('page_isvalid_unknown');
7740         }
7741         public function getTheme()
7742         {
7743                 if(is_string($this->_theme))
7744                         $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
7745                 return $this->_theme;
7746         }
7747         public function setTheme($value)
7748         {
7749                 $this->_theme=empty($value)?null:$value;
7750         }
7751         public function getStyleSheetTheme()
7752         {
7753                 if(is_string($this->_styleSheet))
7754                         $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
7755                 return $this->_styleSheet;
7756         }
7757         public function setStyleSheetTheme($value)
7758         {
7759                 $this->_styleSheet=empty($value)?null:$value;
7760         }
7761         public function applyControlSkin($control)
7762         {
7763                 if(($theme=$this->getTheme())!==null)
7764                         $theme->applySkin($control);
7765         }
7766         public function applyControlStyleSheet($control)
7767         {
7768                 if(($theme=$this->getStyleSheetTheme())!==null)
7769                         $theme->applySkin($control);
7770         }
7771         public function getClientScript()
7772         {
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);
7781                 }
7782                 return $this->_clientScript;
7783         }
7784         public function onPreInit($param)
7785         {
7786                 $this->raiseEvent('OnPreInit',$this,$param);
7787         }
7788         public function onInitComplete($param)
7789         {
7790                 $this->raiseEvent('OnInitComplete',$this,$param);
7791         }
7792         public function onPreLoad($param)
7793         {
7794                 $this->raiseEvent('OnPreLoad',$this,$param);
7795         }
7796         public function onLoadComplete($param)
7797         {
7798                 $this->raiseEvent('OnLoadComplete',$this,$param);
7799         }
7800         public function onPreRenderComplete($param)
7801         {
7802                 $this->raiseEvent('OnPreRenderComplete',$this,$param);
7803                 $cs=$this->getClientScript();
7804                 $theme=$this->getTheme();
7805                 if($theme instanceof ITheme)
7806                 {
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);
7811                 }
7812                 $styleSheet=$this->getStyleSheetTheme();
7813                 if($styleSheet instanceof ITheme)
7814                 {
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);
7819                 }
7820                 if($cs->getRequiresHead() && $this->getHead()===null)
7821                         throw new TConfigurationException('page_head_required');
7822         }
7823         private function getCssMediaType($url)
7824         {
7825                 $segs=explode('.',basename($url));
7826                 if(isset($segs[2]))
7827                         return $segs[count($segs)-2];
7828                 else
7829                         return '';
7830         }
7831         public function onSaveStateComplete($param)
7832         {
7833                 $this->raiseEvent('OnSaveStateComplete',$this,$param);
7834         }
7835         private function determinePostBackMode()
7836         {
7837                 $postData=$this->getRequest();
7838                 if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
7839                         $this->_postData=$postData;
7840         }
7841         public function getIsPostBack()
7842         {
7843                 return $this->_postData!==null;
7844         }
7845         public function getIsCallback()
7846         {
7847                 return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
7848         }
7849         public function saveState()
7850         {
7851                 parent::saveState();
7852                 $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
7853         }
7854         public function loadState()
7855         {
7856                 parent::loadState();
7857                 $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
7858         }
7859         protected function loadPageState()
7860         {
7861                 $state=$this->getStatePersister()->load();
7862                 $this->loadStateRecursive($state,$this->getEnableViewState());
7863         }
7864         protected function savePageState()
7865         {
7866                 $state=&$this->saveStateRecursive($this->getEnableViewState());
7867                 $this->getStatePersister()->save($state);
7868         }
7869         protected function isSystemPostField($field)
7870         {
7871                 return isset(self::$_systemPostFields[$field]);
7872         }
7873         public function registerRequiresPostData($control)
7874         {
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));
7880         }
7881         public function getPostBackEventTarget()
7882         {
7883                 if($this->_postBackEventTarget===null && $this->_postData!==null)
7884                 {
7885                         $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
7886                         if(!empty($eventTarget))
7887                                 $this->_postBackEventTarget=$this->findControl($eventTarget);
7888                 }
7889                 return $this->_postBackEventTarget;
7890         }
7891         public function setPostBackEventTarget(TControl $control)
7892         {
7893                 $this->_postBackEventTarget=$control;
7894         }
7895         public function getPostBackEventParameter()
7896         {
7897                 if($this->_postBackEventParameter===null && $this->_postData!==null)
7898                 {
7899                         if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
7900                                 $this->_postBackEventParameter='';
7901                 }
7902                 return $this->_postBackEventParameter;
7903         }
7904         public function setPostBackEventParameter($value)
7905         {
7906                 $this->_postBackEventParameter=$value;
7907         }
7908         protected function processPostData($postData,$beforeLoad)
7909         {
7910                 $this->_isLoadingPostData=true;
7911                 if($beforeLoad)
7912                         $this->_restPostData=new TMap;
7913                 foreach($postData as $key=>$value)
7914                 {
7915                         if($this->isSystemPostField($key))
7916                                 continue;
7917                         else if($control=$this->findControl($key))
7918                         {
7919                                 if($control instanceof IPostBackDataHandler)
7920                                 {
7921                                         if($control->loadPostData($key,$postData))
7922                                                 $this->_controlsPostDataChanged[]=$control;
7923                                 }
7924                                 else if($control instanceof IPostBackEventHandler &&
7925                                         empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
7926                                 {
7927                                         $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);                                }
7928                                 unset($this->_controlsRequiringPostData[$key]);
7929                         }
7930                         else if($beforeLoad)
7931                                 $this->_restPostData->add($key,$value);
7932                 }
7933                 foreach($this->_controlsRequiringPostData as $key=>$value)
7934                 {
7935                         if($control=$this->findControl($key))
7936                         {
7937                                 if($control instanceof IPostBackDataHandler)
7938                                 {
7939                                         if($control->loadPostData($key,$this->_postData))
7940                                                 $this->_controlsPostDataChanged[]=$control;
7941                                 }
7942                                 else
7943                                         throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
7944                                 unset($this->_controlsRequiringPostData[$key]);
7945                         }
7946                 }
7947                 $this->_isLoadingPostData=false;
7948         }
7949         public function getIsLoadingPostData()
7950         {
7951                 return $this->_isLoadingPostData;
7952         }
7953         protected function raiseChangedEvents()
7954         {
7955                 foreach($this->_controlsPostDataChanged as $control)
7956                         $control->raisePostDataChangedEvent();
7957         }
7958         protected function raisePostBackEvent()
7959         {
7960                 if(($postBackHandler=$this->getPostBackEventTarget())===null)
7961                         $this->validate();
7962                 else if($postBackHandler instanceof IPostBackEventHandler)
7963                         $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
7964         }
7965         public function getInFormRender()
7966         {
7967                 return $this->_inFormRender;
7968         }
7969         public function ensureRenderInForm($control)
7970         {
7971                 if(!$this->getIsCallback() && !$this->_inFormRender)
7972                         throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
7973         }
7974         public function beginFormRender($writer)
7975         {
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;
7981         }
7982         public function endFormRender($writer)
7983         {
7984                 if($this->_focus)
7985                 {
7986                         if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
7987                                 $focus=$this->_focus->getClientID();
7988                         else
7989                                 $focus=$this->_focus;
7990                         $this->getClientScript()->registerFocusControl($focus);
7991                 }
7992                 else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
7993                         $this->getClientScript()->registerFocusControl($lastFocus);
7994                 $this->_inFormRender=false;
7995         }
7996         public function setFocus($value)
7997         {
7998                 $this->_focus=$value;
7999         }
8000         public function getClientSupportsJavaScript()
8001         {
8002                 return $this->_enableJavaScript;
8003         }
8004         public function setClientSupportsJavaScript($value)
8005         {
8006                 $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
8007         }
8008         public function getHead()
8009         {
8010                 return $this->_head;
8011         }
8012         public function setHead(THead $value)
8013         {
8014                 if($this->_head)
8015                         throw new TInvalidOperationException('page_head_duplicated');
8016                 $this->_head=$value;
8017                 if($this->_title!==null)
8018                 {
8019                         $this->_head->setTitle($this->_title);
8020                         $this->_title=null;
8021                 }
8022         }
8023         public function getTitle()
8024         {
8025                 if($this->_head)
8026                         return $this->_head->getTitle();
8027                 else
8028                         return $this->_title===null ? '' : $this->_title;
8029         }
8030         public function setTitle($value)
8031         {
8032                 if($this->_head)
8033                         $this->_head->setTitle($value);
8034                 else
8035                         $this->_title=$value;
8036         }
8037         public function getClientState()
8038         {
8039                 return $this->_clientState;
8040         }
8041         public function setClientState($state)
8042         {
8043                 $this->_clientState=$state;
8044         }
8045         public function getRequestClientState()
8046         {
8047                 return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
8048         }
8049         public function getStatePersisterClass()
8050         {
8051                 return $this->_statePersisterClass;
8052         }
8053         public function setStatePersisterClass($value)
8054         {
8055                 $this->_statePersisterClass=$value;
8056         }
8057         public function getStatePersister()
8058         {
8059                 if($this->_statePersister===null)
8060                 {
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);
8065                 }
8066                 return $this->_statePersister;
8067         }
8068         public function getEnableStateValidation()
8069         {
8070                 return $this->_enableStateValidation;
8071         }
8072         public function setEnableStateValidation($value)
8073         {
8074                 $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
8075         }
8076         public function getEnableStateEncryption()
8077         {
8078                 return $this->_enableStateEncryption;
8079         }
8080         public function setEnableStateEncryption($value)
8081         {
8082                 $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
8083         }
8084         public function getEnableStateCompression()
8085         {
8086                 return $this->_enableStateCompression;
8087         }
8088         public function setEnableStateCompression($value)
8089         {
8090                 $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
8091         }
8092         public function getPagePath()
8093         {
8094                 return $this->_pagePath;
8095         }
8096         public function setPagePath($value)
8097         {
8098                 $this->_pagePath=$value;
8099         }
8100         public function registerCachingAction($context,$funcName,$funcParams)
8101         {
8102                 if($this->_cachingStack)
8103                 {
8104                         foreach($this->_cachingStack as $cache)
8105                                 $cache->registerAction($context,$funcName,$funcParams);
8106                 }
8107         }
8108         public function getCachingStack()
8109         {
8110                 if(!$this->_cachingStack)
8111                         $this->_cachingStack=new TStack;
8112                 return $this->_cachingStack;
8113         }
8114         public function flushWriter()
8115         {
8116                 if ($this->_writer)
8117                         $this->Response->write($this->_writer->flush());
8118         }
8119 }
8120 interface IPageStatePersister
8121 {
8122         public function getPage();
8123         public function setPage(TPage $page);
8124         public function save($state);
8125         public function load();
8126 }
8127 class TPageStateFormatter
8128 {
8129         public static function serialize($page,$data)
8130         {
8131                 $sm=$page->getApplication()->getSecurityManager();
8132                 if($page->getEnableStateValidation())
8133                         $str=$sm->hashData(serialize($data));
8134                 else
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);
8141         }
8142         public static function unserialize($page,$data)
8143         {
8144                 $str=base64_decode($data);
8145                 if($str==='')
8146                         return null;
8147                 if($str!==false)
8148                 {
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())
8155                         {
8156                                 if(($str=$sm->validateData($str))!==false)
8157                                         return unserialize($str);
8158                         }
8159                         else
8160                                 return unserialize($str);
8161                 }
8162                 return null;
8163         }
8164 }
8165 class TOutputCache extends TControl implements INamingContainer
8166 {
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;
8175         private $_contents;
8176         private $_state;
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()
8184         {
8185                 $this->determineCacheability();
8186                 return !$this->_dataCached;
8187         }
8188         private function determineCacheability()
8189         {
8190                 if(!$this->_cacheChecked)
8191                 {
8192                         $this->_cacheChecked=true;
8193                         if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
8194                         {
8195                                 if($this->_cacheModuleID!=='')
8196                                 {
8197                                         $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
8198                                         if(!($this->_cache instanceof ICache))
8199                                                 throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
8200                                 }
8201                                 else
8202                                         $this->_cache=$this->getApplication()->getCache();
8203                                 if($this->_cache!==null)
8204                                 {
8205                                         $this->_cacheAvailable=true;
8206                                         $data=$this->_cache->get($this->getCacheKey());
8207                                         if(is_array($data))
8208                                         {
8209                                                 $param=new TOutputCacheCheckDependencyEventParameter;
8210                                                 $param->setCacheTime(isset($data[3])?$data[3]:0);
8211                                                 $this->onCheckDependency($param);
8212                                                 $this->_dataCached=$param->getIsValid();
8213                                         }
8214                                         else
8215                                                 $this->_dataCached=false;
8216                                         if($this->_dataCached)
8217                                                 list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
8218                                 }
8219                         }
8220                 }
8221         }
8222         protected function initRecursive($namingContainer=null)
8223         {
8224                 if($this->_cacheAvailable && !$this->_dataCached)
8225                 {
8226                         $stack=$this->getPage()->getCachingStack();
8227                         $stack->push($this);
8228                         parent::initRecursive($namingContainer);
8229                         $stack->pop();
8230                 }
8231                 else
8232                         parent::initRecursive($namingContainer);
8233         }
8234         protected function loadRecursive()
8235         {
8236                 if($this->_cacheAvailable && !$this->_dataCached)
8237                 {
8238                         $stack=$this->getPage()->getCachingStack();
8239                         $stack->push($this);
8240                         parent::loadRecursive();
8241                         $stack->pop();
8242                 }
8243                 else
8244                 {
8245                         if($this->_dataCached)
8246                                 $this->performActions();
8247                         parent::loadRecursive();
8248                 }
8249         }
8250         private function performActions()
8251         {
8252                 $page=$this->getPage();
8253                 $cs=$page->getClientScript();
8254                 foreach($this->_actions as $action)
8255                 {
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]);
8260                         else
8261                                 call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
8262                 }
8263         }
8264         protected function preRenderRecursive()
8265         {
8266                 if($this->_cacheAvailable && !$this->_dataCached)
8267                 {
8268                         $stack=$this->getPage()->getCachingStack();
8269                         $stack->push($this);
8270                         parent::preRenderRecursive();
8271                         $stack->pop();
8272                 }
8273                 else
8274                         parent::preRenderRecursive();
8275         }
8276         protected function loadStateRecursive(&$state,$needViewState=true)
8277         {
8278                 $st=unserialize($state);
8279                 parent::loadStateRecursive($st,$needViewState);
8280         }
8281         protected function &saveStateRecursive($needViewState=true)
8282         {
8283                 if($this->_dataCached)
8284                         return $this->_state;
8285                 else
8286                 {
8287                         $st=parent::saveStateRecursive($needViewState);
8288                                                 $this->_state=serialize($st);
8289                         return $this->_state;
8290                 }
8291         }
8292         public function registerAction($context,$funcName,$funcParams)
8293         {
8294                 $this->_actions[]=array($context,$funcName,$funcParams);
8295         }
8296         public function getCacheKey()
8297         {
8298                 if($this->_cacheKey===null)
8299                         $this->_cacheKey=$this->calculateCacheKey();
8300                 return $this->_cacheKey;
8301         }
8302         protected function calculateCacheKey()
8303         {
8304                 $key=$this->getBaseCacheKey();
8305                 if($this->_varyBySession)
8306                         $key.=$this->getSession()->getSessionID();
8307                 if($this->_varyByParam!=='')
8308                 {
8309                         $params=array();
8310                         $request=$this->getRequest();
8311                         foreach(explode(',',$this->_varyByParam) as $name)
8312                         {
8313                                 $name=trim($name);
8314                                 $params[$name]=$request->itemAt($name);
8315                         }
8316                         $key.=serialize($params);
8317                 }
8318                 $param=new TOutputCacheCalculateKeyEventParameter;
8319                 $this->onCalculateKey($param);
8320                 $key.=$param->getCacheKey();
8321                 return $key;
8322         }
8323         protected function getBaseCacheKey()
8324         {
8325                 return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
8326         }
8327         public function getCacheModuleID()
8328         {
8329                 return $this->_cacheModuleID;
8330         }
8331         public function setCacheModuleID($value)
8332         {
8333                 $this->_cacheModuleID=$value;
8334         }
8335         public function setCacheKeyPrefix($value)
8336         {
8337                 $this->_keyPrefix=$value;
8338         }
8339         public function getCacheTime()
8340         {
8341                 return $this->_cacheTime;
8342         }
8343         protected function getCacheDependency()
8344         {
8345                 return null;
8346         }
8347         public function getContentCached()
8348         {
8349                 return $this->_dataCached;
8350         }
8351         public function getDuration()
8352         {
8353                 return $this->_duration;
8354         }
8355         public function setDuration($value)
8356         {
8357                 if(($value=TPropertyValue::ensureInteger($value))<0)
8358                         throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
8359                 $this->_duration=$value;
8360         }
8361         public function getVaryByParam()
8362         {
8363                 return $this->_varyByParam;
8364         }
8365         public function setVaryByParam($value)
8366         {
8367                 $this->_varyByParam=trim($value);
8368         }
8369         public function getVaryBySession()
8370         {
8371                 return $this->_varyBySession;
8372         }
8373         public function setVaryBySession($value)
8374         {
8375                 $this->_varyBySession=TPropertyValue::ensureBoolean($value);
8376         }
8377         public function getCachingPostBack()
8378         {
8379                 return $this->_cachePostBack;
8380         }
8381         public function setCachingPostBack($value)
8382         {
8383                 $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
8384         }
8385         public function onCheckDependency($param)
8386         {
8387                 $this->raiseEvent('OnCheckDependency',$this,$param);
8388         }
8389         public function onCalculateKey($param)
8390         {
8391                 $this->raiseEvent('OnCalculateKey',$this,$param);
8392         }
8393         public function render($writer)
8394         {
8395                 if($this->_dataCached)
8396                         $writer->write($this->_contents);
8397                 else if($this->_cacheAvailable)
8398                 {
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);
8405                         $stack->pop();
8406                         $content=$textwriter->flush();
8407                         $data=array($content,$this->_state,$this->_actions,time());
8408                         $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
8409                 }
8410                 else
8411                         parent::render($writer);
8412         }
8413 }
8414 class TOutputCacheCheckDependencyEventParameter extends TEventParameter
8415 {
8416         private $_isValid=true;
8417         private $_cacheTime=0;
8418         public function getIsValid()
8419         {
8420                 return $this->_isValid;
8421         }
8422         public function setIsValid($value)
8423         {
8424                 $this->_isValid=TPropertyValue::ensureBoolean($value);
8425         }
8426         public function getCacheTime()
8427         {
8428                 return $this->_cacheTime;
8429         }
8430         public function setCacheTime($value)
8431         {
8432                 $this->_cacheTime=TPropertyValue::ensureInteger($value);
8433         }
8434 }
8435 class TOutputCacheCalculateKeyEventParameter extends TEventParameter
8436 {
8437         private $_cacheKey='';
8438         public function getCacheKey()
8439         {
8440                 return $this->_cacheKey;
8441         }
8442         public function setCacheKey($value)
8443         {
8444                 $this->_cacheKey=TPropertyValue::ensureString($value);
8445         }
8446 }
8447 class TOutputCacheTextWriterMulti extends TTextWriter
8448 {
8449         protected $_writers;
8450         public function __construct(Array $writers)
8451         {
8452                                 $this->_writers = $writers;
8453         }
8454         public function write($s)
8455         {
8456                 foreach($this->_writers as $writer)
8457                         $writer->write($s);
8458         }
8459         public function flush()
8460         {
8461                 foreach($this->_writers as $writer)
8462                         $s = $writer->flush();
8463                 return $s;
8464         }
8465 }
8466 class TTemplateManager extends TModule
8467 {
8468         const TEMPLATE_FILE_EXT='.tpl';
8469         const TEMPLATE_CACHE_PREFIX='prado:template:';
8470         public function init($config)
8471         {
8472                 $this->getService()->setTemplateManager($this);
8473         }
8474         public function getTemplateByClassName($className)
8475         {
8476                 $class=new ReflectionClass($className);
8477                 $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
8478                 return $this->getTemplateByFileName($tplFile);
8479         }
8480         public function getTemplateByFileName($fileName)
8481         {
8482                 if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
8483                 {
8484                         if(($cache=$this->getApplication()->getCache())===null)
8485                                 return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8486                         else
8487                         {
8488                                 $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
8489                                 if(is_array($array))
8490                                 {
8491                                         list($template,$timestamps)=$array;
8492                                         if($this->getApplication()->getMode()===TApplicationMode::Performance)
8493                                                 return $template;
8494                                         $cacheValid=true;
8495                                         foreach($timestamps as $tplFile=>$timestamp)
8496                                         {
8497                                                 if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
8498                                                 {
8499                                                         $cacheValid=false;
8500                                                         break;
8501                                                 }
8502                                         }
8503                                         if($cacheValid)
8504                                                 return $template;
8505                                 }
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));
8513                                 return $template;
8514                         }
8515                 }
8516                 else
8517                         return null;
8518         }
8519         protected function getLocalizedTemplate($filename)
8520         {
8521                 if(($app=$this->getApplication()->getGlobalization(false))===null)
8522                         return is_file($filename)?$filename:null;
8523                 foreach($app->getLocalizedResource($filename) as $file)
8524                 {
8525                         if(($file=realpath($file))!==false && is_file($file))
8526                                 return $file;
8527                 }
8528                 return null;
8529         }
8530 }
8531 class TTemplate extends TApplicationComponent implements ITemplate
8532 {
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;
8545         private $_content;
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)
8553         {
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()
8563         {
8564                 return $this->_tplFile;
8565         }
8566         public function getIsSourceTemplate()
8567         {
8568                 return $this->_sourceTemplate;
8569         }
8570         public function getContextPath()
8571         {
8572                 return $this->_contextPath;
8573         }
8574         public function getDirective()
8575         {
8576                 return $this->_directive;
8577         }
8578         public function getHashCode()
8579         {
8580                 return $this->_hashCode;
8581         }
8582         public function &getItems()
8583         {
8584                 return $this->_tpl;
8585         }
8586         public function instantiateIn($tplControl,$parentControl=null)
8587         {
8588                 $this->_tplControl=$tplControl;
8589                 if($parentControl===null)
8590                         $parentControl=$tplControl;
8591                 if(($page=$tplControl->getPage())===null)
8592                         $page=$this->getService()->getRequestedPage();
8593                 $controls=array();
8594                 $directChildren=array();
8595                 foreach($this->_tpl as $key=>$object)
8596                 {
8597                         if($object[0]===-1)
8598                                 $parent=$parentControl;
8599                         else if(isset($controls[$object[0]]))
8600                                 $parent=$controls[$object[0]];
8601                         else
8602                                 continue;
8603                         if(isset($object[2]))                           {
8604                                 $component=Prado::createComponent($object[1]);
8605                                 $properties=&$object[2];
8606                                 if($component instanceof TControl)
8607                                 {
8608                                         if($component instanceof TOutputCache)
8609                                                 $component->setCacheKeyPrefix($this->_hashCode.$key);
8610                                         $component->setTemplateControl($tplControl);
8611                                         if(isset($properties['id']))
8612                                         {
8613                                                 if(is_array($properties['id']))
8614                                                         $properties['id']=$component->evaluateExpression($properties['id'][1]);
8615                                                 $tplControl->registerObject($properties['id'],$component);
8616                                         }
8617                                         if(isset($properties['skinid']))
8618                                         {
8619                                                 if(is_array($properties['skinid']))
8620                                                         $component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
8621                                                 else
8622                                                         $component->setSkinID($properties['skinid']);
8623                                                 unset($properties['skinid']);
8624                                         }
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;
8632                                         else
8633                                                 $component->createdOnTemplate($parent);
8634                                         if($component->getAllowChildControls())
8635                                                 $controls[$key]=$component;
8636                                 }
8637                                 else if($component instanceof TComponent)
8638                                 {
8639                                         $controls[$key]=$component;
8640                                         if(isset($properties['id']))
8641                                         {
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']);
8647                                         }
8648                                         foreach($properties as $name=>$value)
8649                                                 $this->configureComponent($component,$name,$value);
8650                                         if($parent===$parentControl)
8651                                                 $directChildren[]=$component;
8652                                         else
8653                                                 $component->createdOnTemplate($parent);
8654                                 }
8655                         }
8656                         else
8657                         {
8658                                 if($object[1] instanceof TCompositeLiteral)
8659                                 {
8660                                                                                 $o=clone $object[1];
8661                                         $o->setContainer($tplControl);
8662                                         if($parent===$parentControl)
8663                                                 $directChildren[]=$o;
8664                                         else
8665                                                 $parent->addParsedObject($o);
8666                                 }
8667                                 else
8668                                 {
8669                                         if($parent===$parentControl)
8670                                                 $directChildren[]=$object[1];
8671                                         else
8672                                                 $parent->addParsedObject($object[1]);
8673                                 }
8674                         }
8675                 }
8676                                                                 foreach($directChildren as $control)
8677                 {
8678                         if($control instanceof TComponent)
8679                                 $control->createdOnTemplate($parentControl);
8680                         else
8681                                 $parentControl->addParsedObject($control);
8682                 }
8683         }
8684         protected function configureControl($control,$name,$value)
8685         {
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);
8689         }
8690         protected function configureComponent($component,$name,$value)
8691         {
8692                 if(strpos($name,'.')===false)                           $this->configureProperty($component,$name,$value);
8693                 else                            $this->configureSubProperty($component,$name,$value);
8694         }
8695         protected function configureEvent($control,$name,$value,$contextControl)
8696         {
8697                 if(strpos($value,'.')===false)
8698                         $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
8699                 else
8700                         $control->attachEventHandler($name,array($contextControl,$value));
8701         }
8702         protected function configureProperty($component,$name,$value)
8703         {
8704                 if(is_array($value))
8705                 {
8706                         switch($value[0])
8707                         {
8708                                 case self::CONFIG_DATABIND:
8709                                         $component->bindProperty($name,$value[1]);
8710                                         break;
8711                                 case self::CONFIG_EXPRESSION:
8712                                         if($component instanceof TControl)
8713                                                 $component->autoBindProperty($name,$value[1]);
8714                                         else
8715                                         {
8716                                                 $setter='set'.$name;
8717                                                 $component->$setter($this->_tplControl->evaluateExpression($value[1]));
8718                                         }
8719                                         break;
8720                                 case self::CONFIG_TEMPLATE:
8721                                         $setter='set'.$name;
8722                                         $component->$setter($value[1]);
8723                                         break;
8724                                 case self::CONFIG_ASSET:                                                        $setter='set'.$name;
8725                                         $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
8726                                         $component->$setter($url);
8727                                         break;
8728                                 case self::CONFIG_PARAMETER:                                                    $setter='set'.$name;
8729                                         $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
8730                                         break;
8731                                 case self::CONFIG_LOCALIZATION:
8732                                         $setter='set'.$name;
8733                                         $component->$setter(Prado::localize($value[1]));
8734                                         break;
8735                                 default:                                                throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
8736                                         break;
8737                         }
8738                 }
8739                 else
8740                 {
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);
8746                 }
8747         }
8748         protected function configureSubProperty($component,$name,$value)
8749         {
8750                 if(is_array($value))
8751                 {
8752                         switch($value[0])
8753                         {
8754                                 case self::CONFIG_DATABIND:                                                     $component->bindProperty($name,$value[1]);
8755                                         break;
8756                                 case self::CONFIG_EXPRESSION:                                                   if($component instanceof TControl)
8757                                                 $component->autoBindProperty($name,$value[1]);
8758                                         else
8759                                                 $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
8760                                         break;
8761                                 case self::CONFIG_TEMPLATE:
8762                                         $component->setSubProperty($name,$value[1]);
8763                                         break;
8764                                 case self::CONFIG_ASSET:                                                        $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
8765                                         $component->setSubProperty($name,$url);
8766                                         break;
8767                                 case self::CONFIG_PARAMETER:                                                    $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
8768                                         break;
8769                                 case self::CONFIG_LOCALIZATION:
8770                                         $component->setSubProperty($name,Prado::localize($value[1]));
8771                                         break;
8772                                 default:                                                throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
8773                                         break;
8774                         }
8775                 }
8776                 else
8777                         $component->setSubProperty($name,$value);
8778         }
8779         protected function parse($input)
8780         {
8781                 $input=$this->preprocess($input);
8782                 $tpl=&$this->_tpl;
8783                 $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
8784                 $expectPropEnd=false;
8785                 $textStart=0;
8786                                 $stack=array();
8787                 $container=-1;
8788                 $matchEnd=0;
8789                 $c=0;
8790                 $this->_directive=null;
8791                 try
8792                 {
8793                         for($i=0;$i<$n;++$i)
8794                         {
8795                                 $match=&$matches[$i];
8796                                 $str=$match[0][0];
8797                                 $matchStart=$match[0][1];
8798                                 $matchEnd=$matchStart+strlen($str)-1;
8799                                 if(strpos($str,'<com:')===0)                                    {
8800                                         if($expectPropEnd)
8801                                                 continue;
8802                                         if($matchStart>$textStart)
8803                                                 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8804                                         $textStart=$matchEnd+1;
8805                                         $type=$match[1][0];
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]!=='/')                                          {
8810                                                 $stack[] = $type;
8811                                                 $container=$c-1;
8812                                         }
8813                                 }
8814                                 else if(strpos($str,'</com:')===0)                                      {
8815                                         if($expectPropEnd)
8816                                                 continue;
8817                                         if($matchStart>$textStart)
8818                                                 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8819                                         $textStart=$matchEnd+1;
8820                                         $type=$match[1][0];
8821                                         if(empty($stack))
8822                                                 throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
8823                                         $name=array_pop($stack);
8824                                         if($name!==$type)
8825                                         {
8826                                                 $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8827                                                 throw new TConfigurationException('template_closingtag_expected',$tag);
8828                                         }
8829                                         $container=$tpl[$container][0];
8830                                 }
8831                                 else if(strpos($str,'<%@')===0)                                 {
8832                                         if($expectPropEnd)
8833                                                 continue;
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]);
8840                                 }
8841                                 else if(strpos($str,'<%')===0)                                  {
8842                                         if($expectPropEnd)
8843                                                 continue;
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]==='[')
8859                                         {
8860                                                 $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
8861                                                 $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
8862                                         }
8863                                 }
8864                                 else if(strpos($str,'<prop:')===0)                                      {
8865                                         if(strrpos($str,'/>')===strlen($str)-2)                                         {
8866                                                 if($expectPropEnd)
8867                                                         continue;
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)
8879                                                 {
8880                                                         if(isset($tpl[$container][2][$name]))
8881                                                                 throw new TConfigurationException('template_property_duplicated',$name);
8882                                                         $tpl[$container][2][$name]=$value;
8883                                                 }
8884                                         }
8885                                         else                                    {
8886                                                 $prop=strtolower($match[3][0]);
8887                                                 $stack[] = '@'.$prop;
8888                                                 if(!$expectPropEnd)
8889                                                 {
8890                                                         if($matchStart>$textStart)
8891                                                                 $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8892                                                         $textStart=$matchEnd+1;
8893                                                         $expectPropEnd=true;
8894                                                 }
8895                                         }
8896                                 }
8897                                 else if(strpos($str,'</prop:')===0)                                     {
8898                                         $prop=strtolower($match[3][0]);
8899                                         if(empty($stack))
8900                                                 throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
8901                                         $name=array_pop($stack);
8902                                         if($name!=='@'.$prop)
8903                                         {
8904                                                 $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8905                                                 throw new TConfigurationException('template_closingtag_expected',$tag);
8906                                         }
8907                                         if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
8908                                         {
8909                                                 if($matchStart>$textStart)
8910                                                 {
8911                                                         $value=substr($input,$textStart,$matchStart-$textStart);
8912                                                         if(substr($prop,-8,8)==='template')
8913                                                                 $value=$this->parseTemplateProperty($value,$textStart);
8914                                                         else
8915                                                                 $value=$this->parseAttribute($value);
8916                                                         if($container>=0)
8917                                                         {
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;
8923                                                         }
8924                                                         else                                                                    $this->_directive[$prop]=$value;
8925                                                         $textStart=$matchEnd+1;
8926                                                 }
8927                                                 $expectPropEnd=false;
8928                                         }
8929                                 }
8930                                 else if(strpos($str,'<!--')===0)                                        {
8931                                         if($expectPropEnd)
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;
8936                                 }
8937                                 else
8938                                         throw new TConfigurationException('template_matching_unexpected',$match);
8939                         }
8940                         if(!empty($stack))
8941                         {
8942                                 $name=array_pop($stack);
8943                                 $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8944                                 throw new TConfigurationException('template_closingtag_expected',$tag);
8945                         }
8946                         if($textStart<strlen($input))
8947                                 $tpl[$c++]=array($container,substr($input,$textStart));
8948                 }
8949                 catch(Exception $e)
8950                 {
8951                         if(($e instanceof TException) && ($e instanceof TTemplateException))
8952                                 throw $e;
8953                         if($matchEnd===0)
8954                                 $line=$this->_startingLine+1;
8955                         else
8956                                 $line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
8957                         $this->handleException($e,$line,$input);
8958                 }
8959                 if($this->_directive===null)
8960                         $this->_directive=array();
8961                                 $objects=array();
8962                 $parent=null;
8963                 $merged=array();
8964                 foreach($tpl as $id=>$object)
8965                 {
8966                         if(isset($object[2]) || $object[0]!==$parent)
8967                         {
8968                                 if($parent!==null)
8969                                 {
8970                                         if(count($merged[1])===1 && is_string($merged[1][0]))
8971                                                 $objects[$id-1]=array($merged[0],$merged[1][0]);
8972                                         else
8973                                                 $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
8974                                 }
8975                                 if(isset($object[2]))
8976                                 {
8977                                         $parent=null;
8978                                         $objects[$id]=$object;
8979                                 }
8980                                 else
8981                                 {
8982                                         $parent=$object[0];
8983                                         $merged=array($parent,array($object[1]));
8984                                 }
8985                         }
8986                         else
8987                                 $merged[1][]=$object[1];
8988                 }
8989                 if($parent!==null)
8990                 {
8991                         if(count($merged[1])===1 && is_string($merged[1][0]))
8992                                 $objects[$id]=array($merged[0],$merged[1][0]);
8993                         else
8994                                 $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
8995                 }
8996                 $tpl=$objects;
8997                 return $objects;
8998         }
8999         protected function parseAttributes($str,$offset)
9000         {
9001                 if($str==='')
9002                         return array();
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)
9007                 {
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')
9014                         {
9015                                 if($value[0]==='\'' || $value[0]==='"')
9016                                         $attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
9017                                 else
9018                                         $attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
9019                         }
9020                         else
9021                         {
9022                                 if($value[0]==='\'' || $value[0]==='"')
9023                                         $attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
9024                                 else
9025                                         $attributes[$name]=$this->parseAttribute($value);
9026                         }
9027                 }
9028                 return $attributes;
9029         }
9030         protected function parseTemplateProperty($content,$offset)
9031         {
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));
9034         }
9035         protected function parseAttribute($value)
9036         {
9037                 if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
9038                 {
9039                         $isDataBind=false;
9040                         $textStart=0;
9041                         $expr='';
9042                         for($i=0;$i<$n;++$i)
9043                         {
9044                                 $match=$matches[0][$i];
9045                                 $token=$match[0];
9046                                 $offset=$match[1];
9047                                 $length=strlen($token);
9048                                 if($token[2]==='#')
9049                                         $isDataBind=true;
9050                                 if($offset>$textStart)
9051                                         $expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
9052                                 $expr.='.('.substr($token,3,$length-5).')';
9053                                 $textStart=$offset+$length;
9054                         }
9055                         $length=strlen($value);
9056                         if($length>$textStart)
9057                                 $expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
9058                         if($isDataBind)
9059                                 return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
9060                         else
9061                                 return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
9062                 }
9063                 else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
9064                 {
9065                         $value=$matches[1];
9066                         if($value[2]==='~')
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'");
9075                         }
9076                 }
9077                 else
9078                         return $value;
9079         }
9080         protected function validateAttributes($type,$attributes)
9081         {
9082                 Prado::using($type);
9083                 if(($pos=strrpos($type,'.'))!==false)
9084                         $className=substr($type,$pos+1);
9085                 else
9086                         $className=$type;
9087                 $class=new ReflectionClass($className);
9088                 if(is_subclass_of($className,'TControl') || $className==='TControl')
9089                 {
9090                         foreach($attributes as $name=>$att)
9091                         {
9092                                 if(($pos=strpos($name,'.'))!==false)
9093                                 {
9094                                                                                 $subname=substr($name,0,$pos);
9095                                         if(!$class->hasMethod('get'.$subname))
9096                                                 throw new TConfigurationException('template_property_unknown',$type,$subname);
9097                                 }
9098                                 else if(strncasecmp($name,'on',2)===0)
9099                                 {
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);
9104                                 }
9105                                 else
9106                                 {
9107                                                                                 if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)) )
9108                                         {
9109                                                 if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
9110                                                         throw new TConfigurationException('template_property_readonly',$type,$name);
9111                                                 else
9112                                                         throw new TConfigurationException('template_property_unknown',$type,$name);
9113                                         }
9114                                         else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
9115                                         {
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);
9120                                         }
9121                                 }
9122                         }
9123                 }
9124                 else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
9125                 {
9126                         foreach($attributes as $name=>$att)
9127                         {
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)
9131                                 {
9132                                                                                 $subname=substr($name,0,$pos);
9133                                         if(!$class->hasMethod('get'.$subname))
9134                                                 throw new TConfigurationException('template_property_unknown',$type,$subname);
9135                                 }
9136                                 else if(strncasecmp($name,'on',2)===0)
9137                                         throw new TConfigurationException('template_event_forbidden',$type,$name);
9138                                 else
9139                                 {
9140                                                                                 if(strcasecmp($name,'id')!==0 && !($class->hasMethod('set'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)))
9141                                         {
9142                                                 if($class->hasMethod('get'.$name))
9143                                                         throw new TConfigurationException('template_property_readonly',$type,$name);
9144                                                 else
9145                                                         throw new TConfigurationException('template_property_unknown',$type,$name);
9146                                         }
9147                                 }
9148                         }
9149                 }
9150                 else
9151                         throw new TConfigurationException('template_component_required',$type);
9152         }
9153         public function getIncludedFiles()
9154         {
9155                 return $this->_includedFiles;
9156         }
9157         protected function handleException($e,$line,$input=null)
9158         {
9159                 $srcFile=$this->_tplFile;
9160                 if(($n=count($this->_includedFiles))>0)                 {
9161                         for($i=$n-1;$i>=0;--$i)
9162                         {
9163                                 if($this->_includeAtLine[$i]<=$line)
9164                                 {
9165                                         if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
9166                                         {
9167                                                 $line=$line-$this->_includeAtLine[$i]+1;
9168                                                 $srcFile=$this->_includedFiles[$i];
9169                                                 break;
9170                                         }
9171                                         else
9172                                                 $line=$line-$this->_includeLines[$i]+1;
9173                                 }
9174                         }
9175                 }
9176                 $exception=new TTemplateException('template_format_invalid',$e->getMessage());
9177                 $exception->setLineNumber($line);
9178                 if(!empty($srcFile))
9179                         $exception->setTemplateFile($srcFile);
9180                 else
9181                         $exception->setTemplateSource($input);
9182                 throw $exception;
9183         }
9184         protected function preprocess($input)
9185         {
9186                 if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
9187                 {
9188                         for($i=0;$i<$n;++$i)
9189                         {
9190                                 $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
9191                                 if($filePath!==null && is_file($filePath))
9192                                         $this->_includedFiles[]=$filePath;
9193                                 else
9194                                 {
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);
9197                                 }
9198                         }
9199                         $base=0;
9200                         for($i=0;$i<$n;++$i)
9201                         {
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;
9209                         }
9210                 }
9211                 return $input;
9212         }
9213         protected function isClassBehaviorMethod(ReflectionClass $class,$method)
9214         {
9215           $component=new ReflectionClass('TComponent');
9216           $behaviors=$component->getStaticProperties();
9217           if(!isset($behaviors['_um']))
9218             return false;
9219           foreach($behaviors['_um'] as $name=>$list)
9220           {
9221             if(strtolower($class->getShortName())!==$name && !$class->isSubclassOf($name)) continue;
9222             foreach($list as $param)
9223             {
9224               if(method_exists($param->getBehavior(),$method))
9225                 return true;
9226             }
9227           }
9228           return false;
9229         }
9230 }
9231 class TThemeManager extends TModule
9232 {
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)
9240         {
9241                 $this->_initialized=true;
9242                 $service=$this->getService();
9243                 if($service instanceof TPageService)
9244                         $service->setThemeManager($this);
9245                 else
9246                         throw new TConfigurationException('thememanager_service_unavailable');
9247         }
9248         public function getTheme($name)
9249         {
9250                 $themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
9251                 $themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
9252                 return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
9253         }
9254         public function setThemeClass($class) {
9255                 $this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
9256         }
9257         public function getThemeClass() {
9258                 return $this->_themeClass;
9259         }
9260         public function getAvailableThemes()
9261         {
9262                 $themes=array();
9263                 $basePath=$this->getBasePath();
9264                 $folder=@opendir($basePath);
9265                 while($file=@readdir($folder))
9266                 {
9267                         if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
9268                                 $themes[]=$file;
9269                 }
9270                 closedir($folder);
9271                 return $themes;
9272         }
9273         public function getBasePath()
9274         {
9275                 if($this->_basePath===null)
9276                 {
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;
9281                 }
9282                 return $this->_basePath;
9283         }
9284         public function setBasePath($value)
9285         {
9286                 if($this->_initialized)
9287                         throw new TInvalidOperationException('thememanager_basepath_unchangeable');
9288                 else
9289                 {
9290                         $this->_basePath=Prado::getPathOfNamespace($value);
9291                         if($this->_basePath===null || !is_dir($this->_basePath))
9292                                 throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
9293                 }
9294         }
9295         public function getBaseUrl()
9296         {
9297                 if($this->_baseUrl===null)
9298                 {
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)),'\\','/');
9305                 }
9306                 return $this->_baseUrl;
9307         }
9308         public function setBaseUrl($value)
9309         {
9310                 $this->_baseUrl=rtrim($value,'/');
9311         }
9312 }
9313 class TTheme extends TApplicationComponent implements ITheme
9314 {
9315         const THEME_CACHE_PREFIX='prado:theme:';
9316         const SKIN_FILE_EXT='.skin';
9317         private $_themePath;
9318         private $_themeUrl;
9319         private $_skins=null;
9320         private $_name='';
9321         private $_cssFiles=array();
9322         private $_jsFiles=array();
9323         public function __construct($themePath,$themeUrl)
9324         {
9325                 $this->_themeUrl=$themeUrl;
9326                 $this->_themePath=realpath($themePath);
9327                 $this->_name=basename($themePath);
9328                 $cacheValid=false;
9329                                 if(($cache=$this->getApplication()->getCache())!==null)
9330                 {
9331                         $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
9332                         if(is_array($array))
9333                         {
9334                                 list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
9335                                 if($this->getApplication()->getMode()!==TApplicationMode::Performance)
9336                                 {
9337                                         if(($dir=opendir($themePath))===false)
9338                                                 throw new TIOException('theme_path_inexistent',$themePath);
9339                                         $cacheValid=true;
9340                                         while(($file=readdir($dir))!==false)
9341                                         {
9342                                                 if($file==='.' || $file==='..')
9343                                                         continue;
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)
9349                                                 {
9350                                                         $cacheValid=false;
9351                                                         break;
9352                                                 }
9353                                         }
9354                                         closedir($dir);
9355                                         if($cacheValid)
9356                                                 $this->_skins=$skins;
9357                                 }
9358                                 else
9359                                 {
9360                                         $cacheValid=true;
9361                                         $this->_cssFiles=$cssFiles;
9362                                         $this->_jsFiles=$jsFiles;
9363                                         $this->_skins=$skins;
9364                                 }
9365                         }
9366                 }
9367                 if(!$cacheValid)
9368                 {
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)
9375                         {
9376                                 if($file==='.' || $file==='..')
9377                                         continue;
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)
9383                                 {
9384                                         $template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
9385                                         foreach($template->getItems() as $skin)
9386                                         {
9387                                                 if(!isset($skin[2]))                                                    continue;
9388                                                 else if($skin[0]!==-1)
9389                                                         throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
9390                                                 $type=$skin[1];
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];
9396                                         }
9397                                 }
9398                         }
9399                         closedir($dir);
9400                         sort($this->_cssFiles);
9401                         sort($this->_jsFiles);
9402                         if($cache!==null)
9403                                 $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
9404                 }
9405         }
9406         public function getName()
9407         {
9408                 return $this->_name;
9409         }
9410         protected function setName($value)
9411         {
9412                 $this->_name = $value;
9413         }
9414         public function getBaseUrl()
9415         {
9416                 return $this->_themeUrl;
9417         }
9418         protected function setBaseUrl($value)
9419         {
9420                 $this->_themeUrl=rtrim($value,'/');
9421         }
9422         public function getBasePath()
9423         {
9424                 return $this->_themePath;
9425         }
9426         protected function setBasePath($value)
9427         {
9428                 $this->_themePath=$value;
9429         }
9430         public function getSkins()
9431         {
9432                 return $this->_skins;
9433         }
9434         protected function setSkins($value)
9435         {
9436                 $this->_skins = $value;
9437         }
9438         public function applySkin($control)
9439         {
9440                 $type=get_class($control);
9441                 if(($id=$control->getSkinID())==='')
9442                         $id=0;
9443                 if(isset($this->_skins[$type][$id]))
9444                 {
9445                         foreach($this->_skins[$type][$id] as $name=>$value)
9446                         {
9447                                 if(is_array($value))
9448                                 {
9449                                         switch($value[0])
9450                                         {
9451                                                 case TTemplate::CONFIG_EXPRESSION:
9452                                                         $value=$this->evaluateExpression($value[1]);
9453                                                         break;
9454                                                 case TTemplate::CONFIG_ASSET:
9455                                                         $value=$this->_themeUrl.'/'.ltrim($value[1],'/');
9456                                                         break;
9457                                                 case TTemplate::CONFIG_DATABIND:
9458                                                         $control->bindProperty($name,$value[1]);
9459                                                         break;
9460                                                 case TTemplate::CONFIG_PARAMETER:
9461                                                         $control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
9462                                                         break;
9463                                                 case TTemplate::CONFIG_TEMPLATE:
9464                                                         $control->setSubProperty($name,$value[1]);
9465                                                         break;
9466                                                 case TTemplate::CONFIG_LOCALIZATION:
9467                                                         $control->setSubProperty($name,Prado::localize($value[1]));
9468                                                         break;
9469                                                 default:
9470                                                         throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
9471                                                         break;
9472                                         }
9473                                 }
9474                                 if(!is_array($value))
9475                                 {
9476                                         if(strpos($name,'.')===false)                                           {
9477                                                 if($control->hasProperty($name))
9478                                                 {
9479                                                         if($control->canSetProperty($name))
9480                                                         {
9481                                                                 $setter='set'.$name;
9482                                                                 $control->$setter($value);
9483                                                         }
9484                                                         else
9485                                                                 throw new TConfigurationException('theme_property_readonly',$type,$name);
9486                                                 }
9487                                                 else
9488                                                         throw new TConfigurationException('theme_property_undefined',$type,$name);
9489                                         }
9490                                         else                                                    $control->setSubProperty($name,$value);
9491                                 }
9492                         }
9493                         return true;
9494                 }
9495                 else
9496                         return false;
9497         }
9498         public function getStyleSheetFiles()
9499         {
9500                 return $this->_cssFiles;
9501         }
9502         protected function setStyleSheetFiles($value)
9503         {
9504                 $this->_cssFiles=$value;
9505         }
9506         public function getJavaScriptFiles()
9507         {
9508                 return $this->_jsFiles;
9509         }
9510         protected function setJavaScriptFiles($value)
9511         {
9512                 $this->_jsFiles=$value;
9513         }
9514 }
9515 class TPageService extends TService
9516 {
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)
9534         {
9535                 $pageConfig=$this->loadPageConfig($config);
9536                 $this->initPageContext($pageConfig);
9537                 $this->_initialized=true;
9538         }
9539         protected function initPageContext($pageConfig)
9540         {
9541                 $application=$this->getApplication();
9542                 foreach($pageConfig->getApplicationConfigurations() as $appConfig)
9543                         $application->applyConfiguration($appConfig);
9544                 $this->applyConfiguration($pageConfig);
9545         }
9546         protected function applyConfiguration($config)
9547         {
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)
9552                 {
9553                         list($configPagePath,$condition)=$params;
9554                         if($condition!==true)
9555                                 $condition=$this->evaluateExpression($condition);
9556                         if($condition)
9557                         {
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);
9563                         }
9564                 }
9565         }
9566         protected function determineRequestedPagePath()
9567         {
9568                 $pagePath=$this->getRequest()->getServiceParameter();
9569                 if(empty($pagePath))
9570                         $pagePath=$this->getDefaultPage();
9571                 return $pagePath;
9572         }
9573         protected function loadPageConfig($config)
9574         {
9575                 $application=$this->getApplication();
9576                 $pagePath=$this->getRequestedPagePath();
9577                 if(($cache=$application->getCache())===null)
9578                 {
9579                         $pageConfig=new TPageConfiguration($pagePath);
9580                         if($config!==null)
9581                         {
9582                                 if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9583                                         $pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9584                                 else
9585                                         $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9586                         }
9587                         $pageConfig->loadFromFiles($this->getBasePath());
9588                 }
9589                 else
9590                 {
9591                         $configCached=true;
9592                         $currentTimestamp=array();
9593                         $arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
9594                         if(is_array($arr))
9595                         {
9596                                 list($pageConfig,$timestamps)=$arr;
9597                                 if($application->getMode()!==TApplicationMode::Performance)
9598                                 {
9599                                         foreach($timestamps as $fileName=>$timestamp)
9600                                         {
9601                                                 if($fileName===0)                                               {
9602                                                         $appConfigFile=$application->getConfigurationFile();
9603                                                         $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9604                                                         if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
9605                                                                 $configCached=false;
9606                                                 }
9607                                                 else
9608                                                 {
9609                                                         $currentTimestamp[$fileName]=@filemtime($fileName);
9610                                                         if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
9611                                                                 $configCached=false;
9612                                                 }
9613                                         }
9614                                 }
9615                         }
9616                         else
9617                         {
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)
9625                                 {
9626                                         $configFile=$configPath.DIRECTORY_SEPARATOR.$fileName;
9627                                         $currentTimestamp[$configFile]=@filemtime($configFile);
9628                                         $configPath.=DIRECTORY_SEPARATOR.$path;
9629                                 }
9630                                 $appConfigFile=$application->getConfigurationFile();
9631                                 $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9632                         }
9633                         if(!$configCached)
9634                         {
9635                                 $pageConfig=new TPageConfiguration($pagePath);
9636                                 if($config!==null)
9637                                 {
9638                                         if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9639                                                 $pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9640                                         else
9641                                                 $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9642                                 }
9643                                 $pageConfig->loadFromFiles($this->getBasePath());
9644                                 $cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
9645                         }
9646                 }
9647                 return $pageConfig;
9648         }
9649         public function getTemplateManager()
9650         {
9651                 if(!$this->_templateManager)
9652                 {
9653                         $this->_templateManager=new TTemplateManager;
9654                         $this->_templateManager->init(null);
9655                 }
9656                 return $this->_templateManager;
9657         }
9658         public function setTemplateManager(TTemplateManager $value)
9659         {
9660                 $this->_templateManager=$value;
9661         }
9662         public function getThemeManager()
9663         {
9664                 if(!$this->_themeManager)
9665                 {
9666                         $this->_themeManager=new TThemeManager;
9667                         $this->_themeManager->init(null);
9668                 }
9669                 return $this->_themeManager;
9670         }
9671         public function setThemeManager(TThemeManager $value)
9672         {
9673                 $this->_themeManager=$value;
9674         }
9675         public function getRequestedPagePath()
9676         {
9677                 if($this->_pagePath===null)
9678                 {
9679                         $this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
9680                         if(empty($this->_pagePath))
9681                                 throw new THttpException(404,'pageservice_page_required');
9682                 }
9683                 return $this->_pagePath;
9684         }
9685         public function getRequestedPage()
9686         {
9687                 return $this->_page;
9688         }
9689         public function getDefaultPage()
9690         {
9691                 return $this->_defaultPage;
9692         }
9693         public function setDefaultPage($value)
9694         {
9695                 if($this->_initialized)
9696                         throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
9697                 else
9698                         $this->_defaultPage=$value;
9699         }
9700         public function getDefaultPageUrl()
9701         {
9702                 return $this->constructUrl($this->getDefaultPage());
9703         }
9704         public function getBasePath()
9705         {
9706                 if($this->_basePath===null)
9707                 {
9708                         $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9709                         if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9710                         {
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);
9714                         }
9715                 }
9716                 return $this->_basePath;
9717         }
9718         public function setBasePath($value)
9719         {
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);
9725         }
9726         public function setBasePageClass($value)
9727         {
9728                 $this->_basePageClass=$value;
9729         }
9730         public function getBasePageClass()
9731         {
9732                 return $this->_basePageClass;
9733         }
9734         public function setClientScriptManagerClass($value)
9735         {
9736                 $this->_clientScriptManagerClass=$value;
9737         }
9738         public function getClientScriptManagerClass()
9739         {
9740                 return $this->_clientScriptManagerClass;
9741         }
9742         public function run()
9743         {
9744                 $this->_page=$this->createPage($this->getRequestedPagePath());
9745                 $this->runPage($this->_page,$this->_properties);
9746         }
9747         protected function createPage($pagePath)
9748         {
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);
9754                 if($hasClassFile)
9755                 {
9756                         $className=basename($path);
9757                         if(!class_exists($className,false))
9758                                 include_once($path.Prado::CLASS_FILE_EXT);
9759                 }
9760                 else
9761                 {
9762                         $className=$this->getBasePageClass();
9763                         Prado::using($className);
9764                         if(($pos=strrpos($className,'.'))!==false)
9765                                 $className=substr($className,$pos+1);
9766                 }
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));
9773                 return $page;
9774         }
9775         protected function runPage($page,$properties)
9776         {
9777                 foreach($properties as $name=>$value)
9778                         $page->setSubProperty($name,$value);
9779                 $page->run($this->getResponse()->createHtmlWriter());
9780         }
9781         public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
9782         {
9783                 return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
9784         }
9785 }
9786 class TPageConfiguration extends TComponent
9787 {
9788         private $_appConfigs=array();
9789         private $_properties=array();
9790         private $_rules=array();
9791         private $_includes=array();
9792         private $_pagePath='';
9793         public function __construct($pagePath)
9794         {
9795                 $this->_pagePath=$pagePath;
9796         }
9797         public function getExternalConfigurations()
9798         {
9799                 return $this->_includes;
9800         }
9801         public function getProperties()
9802         {
9803                 return $this->_properties;
9804         }
9805         public function getRules()
9806         {
9807                 return $this->_rules;
9808         }
9809         public function getApplicationConfigurations()
9810         {
9811                 return $this->_appConfigs;
9812         }
9813         public function loadFromFiles($basePath)
9814         {
9815                 $paths=explode('.',$this->_pagePath);
9816                 $page=array_pop($paths);
9817                 $path=$basePath;
9818                 $configPagePath='';
9819                 $fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9820                         ? TPageService::CONFIG_FILE_PHP
9821                         : TPageService::CONFIG_FILE_XML;
9822                 foreach($paths as $p)
9823                 {
9824                         $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9825                         $path.=DIRECTORY_SEPARATOR.$p;
9826                         if($configPagePath==='')
9827                                 $configPagePath=$p;
9828                         else
9829                                 $configPagePath.='.'.$p;
9830                 }
9831                 $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9832                 $this->_rules=new TAuthorizationRuleCollection($this->_rules);
9833         }
9834         public function loadFromFile($fname,$configPagePath)
9835         {
9836                 if(empty($fname) || !is_file($fname))
9837                         return;
9838                 if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9839                 {
9840                         $fcontent = include $fname;
9841                         $this->loadFromPhp($fcontent,dirname($fname),$configPagePath);
9842                 }
9843                 else
9844                 {
9845                         $dom=new TXmlDocument;
9846                         if($dom->loadFromFile($fname))
9847                                 $this->loadFromXml($dom,dirname($fname),$configPagePath);
9848                         else
9849                                 throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
9850                 }
9851         }
9852         public function loadFromPhp($config,$configPath,$configPagePath)
9853         {
9854                 $this->loadApplicationConfigurationFromPhp($config,$configPath);
9855                 $this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath);
9856         }
9857         public function loadFromXml($dom,$configPath,$configPagePath)
9858         {
9859                 $this->loadApplicationConfigurationFromXml($dom,$configPath);
9860                 $this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
9861         }
9862         public function loadApplicationConfigurationFromPhp($config,$configPath)
9863         {
9864                 $appConfig=new TApplicationConfiguration;
9865                 $appConfig->loadFromPhp($config,$configPath);
9866                 $this->_appConfigs[]=$appConfig;
9867         }
9868         public function loadApplicationConfigurationFromXml($dom,$configPath)
9869         {
9870                 $appConfig=new TApplicationConfiguration;
9871                 $appConfig->loadFromXml($dom,$configPath);
9872                 $this->_appConfigs[]=$appConfig;
9873         }
9874         public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath)
9875         {
9876                                 if(isset($config['authorization']) && is_array($config['authorization']))
9877                 {
9878                         $rules = array();
9879                         foreach($config['authorization'] as $authorization)
9880                         {
9881                                 $patterns=isset($authorization['pages'])?$authorization['pages']:'';
9882                                 $ruleApplies=false;
9883                                 if(empty($patterns) || trim($patterns)==='*')                                   $ruleApplies=true;
9884                                 else
9885                                 {
9886                                         foreach(explode(',',$patterns) as $pattern)
9887                                         {
9888                                                 if(($pattern=trim($pattern))!=='')
9889                                                 {
9890                                                                                                                 if($configPagePath!=='')                                                                $pattern=$configPagePath.'.'.$pattern;
9891                                                         if(strcasecmp($pattern,$this->_pagePath)===0)
9892                                                         {
9893                                                                 $ruleApplies=true;
9894                                                                 break;
9895                                                         }
9896                                                         if($pattern[strlen($pattern)-1]==='*')                                                  {
9897                                                                 if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9898                                                                 {
9899                                                                         $ruleApplies=true;
9900                                                                         break;
9901                                                                 }
9902                                                         }
9903                                                 }
9904                                         }
9905                                 }
9906                                 if($ruleApplies)
9907                                 {
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);
9914                                 }
9915                         }
9916                         $this->_rules=array_merge($rules,$this->_rules);
9917                 }
9918                                 if(isset($config['pages']) && is_array($config['pages']))
9919                 {
9920                         if(isset($config['pages']['properties']))
9921                         {
9922                                 $this->_properties = array_merge($this->_properties, $config['pages']['properties']);
9923                                 unset($config['pages']['properties']);
9924                         }
9925                         foreach($config['pages'] as $id => $page)
9926                         {
9927                                 $properties = array();
9928                                 if(isset($page['properties']))
9929                                 {
9930                                         $properties=$page['properties'];
9931                                         unset($page['properties']);
9932                                 }
9933                                 $matching=false;
9934                                 $id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
9935                                 if(strcasecmp($id,$this->_pagePath)===0)
9936                                         $matching=true;
9937                                 else if($id[strlen($id)-1]==='*')                                       $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
9938                                 if($matching)
9939                                         $this->_properties=array_merge($this->_properties,$properties);
9940                         }
9941                 }
9942                                 if(isset($config['includes']) && is_array($config['includes']))
9943                 {
9944                         foreach($config['includes'] as $include)
9945                         {
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.')');
9952                                 else
9953                                         $this->_includes[$filePath]=array($configPagePath,$when);
9954                         }
9955                 }
9956         }
9957         public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
9958         {
9959                                 if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
9960                 {
9961                         $rules=array();
9962                         foreach($authorizationNode->getElements() as $node)
9963                         {
9964                                 $patterns=$node->getAttribute('pages');
9965                                 $ruleApplies=false;
9966                                 if(empty($patterns) || trim($patterns)==='*')                                   $ruleApplies=true;
9967                                 else
9968                                 {
9969                                         foreach(explode(',',$patterns) as $pattern)
9970                                         {
9971                                                 if(($pattern=trim($pattern))!=='')
9972                                                 {
9973                                                                                                                 if($configPagePath!=='')                                                                $pattern=$configPagePath.'.'.$pattern;
9974                                                         if(strcasecmp($pattern,$this->_pagePath)===0)
9975                                                         {
9976                                                                 $ruleApplies=true;
9977                                                                 break;
9978                                                         }
9979                                                         if($pattern[strlen($pattern)-1]==='*')                                                  {
9980                                                                 if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9981                                                                 {
9982                                                                         $ruleApplies=true;
9983                                                                         break;
9984                                                                 }
9985                                                         }
9986                                                 }
9987                                         }
9988                                 }
9989                                 if($ruleApplies)
9990                                         $rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
9991                         }
9992                         $this->_rules=array_merge($rules,$this->_rules);
9993                 }
9994                                 if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
9995                 {
9996                         $this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
9997                                                 foreach($pagesNode->getElementsByTagName('page') as $node)
9998                         {
9999                                 $properties=$node->getAttributes();
10000                                 $id=$properties->remove('id');
10001                                 if(empty($id))
10002                                         throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
10003                                 $matching=false;
10004                                 $id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
10005                                 if(strcasecmp($id,$this->_pagePath)===0)
10006                                         $matching=true;
10007                                 else if($id[strlen($id)-1]==='*')                                       $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
10008                                 if($matching)
10009                                         $this->_properties=array_merge($this->_properties,$properties->toArray());
10010                         }
10011                 }
10012                                 foreach($dom->getElementsByTagName('include') as $node)
10013                 {
10014                         if(($when=$node->getAttribute('when'))===null)
10015                                 $when=true;
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.')');
10020                         else
10021                                 $this->_includes[$filePath]=array($configPagePath,$when);
10022                 }
10023         }
10024 }
10025 class TAssetManager extends TModule
10026 {
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)
10035         {
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;
10045         }
10046         public function getBasePath()
10047         {
10048                 return $this->_basePath;
10049         }
10050         public function setBasePath($value)
10051         {
10052                 if($this->_initialized)
10053                         throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
10054                 else
10055                 {
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);
10059                 }
10060         }
10061         public function getBaseUrl()
10062         {
10063                 return $this->_baseUrl;
10064         }
10065         public function setBaseUrl($value)
10066         {
10067                 if($this->_initialized)
10068                         throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
10069                 else
10070                         $this->_baseUrl=rtrim($value,'/');
10071         }
10072         public function publishFilePath($path,$checkTimestamp=false)
10073         {
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))
10079                 {
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;
10086                 }
10087                 else
10088                 {
10089                         $dir=$this->hash($fullpath);
10090                         if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10091                         {
10092                                 $this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
10093                         }
10094                         return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
10095                 }
10096         }
10097         public function getPublished()
10098         {
10099                 return $this->_published;
10100         }
10101         protected function setPublished($values=array())
10102         {
10103                 $this->_published = $values;
10104         }
10105         public function getPublishedPath($path)
10106         {
10107                 $path=realpath($path);
10108                 if(is_file($path))
10109                         return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
10110                 else
10111                         return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
10112         }
10113         public function getPublishedUrl($path)
10114         {
10115                 $path=realpath($path);
10116                 if(is_file($path))
10117                         return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
10118                 else
10119                         return $this->_baseUrl.'/'.$this->hash($path);
10120         }
10121         protected function hash($dir)
10122         {
10123                 return sprintf('%x',crc32($dir.Prado::getVersion()));
10124         }
10125         protected function copyFile($src,$dst)
10126         {
10127                 if(!is_dir($dst))
10128                 {
10129                         @mkdir($dst);
10130                         @chmod($dst, PRADO_CHMOD);
10131                 }
10132                 $dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
10133                 if(@filemtime($dstFile)<@filemtime($src))
10134                 {
10135                         @copy($src,$dstFile);
10136                 }
10137         }
10138         public function copyDirectory($src,$dst)
10139         {
10140                 if(!is_dir($dst))
10141                 {
10142                         @mkdir($dst);
10143                         @chmod($dst, PRADO_CHMOD);
10144                 }
10145                 if($folder=@opendir($src))
10146                 {
10147                         while($file=@readdir($folder))
10148                         {
10149                                 if($file==='.' || $file==='..' || $file==='.svn')
10150                                         continue;
10151                                 else if(is_file($src.DIRECTORY_SEPARATOR.$file))
10152                                 {
10153                                         if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
10154                                         {
10155                                                 @copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10156                                                 @chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
10157                                         }
10158                                 }
10159                                 else
10160                                         $this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10161                         }
10162                         closedir($folder);
10163                 } else {
10164                         throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
10165                 }
10166         }
10167         public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
10168         {
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);
10173                 else
10174                 {
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)
10179                         {
10180                                 if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
10181                                 {
10182                                         $this->copyFile($fullpath,$dst);
10183                                         $this->deployTarFile($tarfile,$dst);
10184                                 }
10185                         }
10186                         return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
10187                 }
10188         }
10189         protected function deployTarFile($path,$destination)
10190         {
10191                 if(($fullpath=realpath($path))===false || !is_file($fullpath))
10192                         throw new TIOException('assetmanager_tarfile_invalid',$path);
10193                 else
10194                 {
10195                         Prado::using('System.IO.TTarFileExtractor');
10196                         $tar = new TTarFileExtractor($fullpath);
10197                         return $tar->extract($destination);
10198                 }
10199         }
10200 }
10201 class TGlobalization extends TModule
10202 {
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)
10210         {
10211                 if($this->_charset===null)
10212                         $this->_charset=$this->getDefaultCharset();
10213                 if($this->_culture===null)
10214                         $this->_culture=$this->getDefaultCulture();
10215                 if($config!==null)
10216                 {
10217                         if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10218                                 $translation = isset($config['translate'])?$config['translate']:null;
10219                         else
10220                         {
10221                                 $t = $config->getElementByTagName('translation');
10222                                 $translation = ($t)?$t->getAttributes():null;
10223                         }
10224                         if($translation)
10225                                 $this->setTranslationConfiguration($translation);
10226                 }
10227                 $this->getApplication()->setGlobalization($this);
10228         }
10229         public function getTranslateDefaultCulture()
10230         {
10231                 return $this->_translateDefaultCulture;
10232         }
10233         public function setTranslateDefaultCulture($value)
10234         {
10235                 $this->_translateDefaultCulture = TPropertyValue::ensureBoolean($value);
10236         }
10237         public function getDefaultCulture()
10238         {
10239                 return $this->_defaultCulture;
10240         }
10241         public function setDefaultCulture($culture)
10242         {
10243                 $this->_defaultCulture = str_replace('-','_',$culture);
10244         }
10245         public function getDefaultCharset()
10246         {
10247                 return $this->_defaultCharset;
10248         }
10249         public function setDefaultCharset($charset)
10250         {
10251                 $this->_defaultCharset = $charset;
10252         }
10253         public function getCulture()
10254         {
10255                 return $this->_culture;
10256         }
10257         public function setCulture($culture)
10258         {
10259                 $this->_culture = str_replace('-','_',$culture);
10260         }
10261         public function getCharset()
10262         {
10263                 return $this->_charset;
10264         }
10265         public function setCharset($charset)
10266         {
10267                 $this->_charset = $charset;
10268         }
10269         public function getTranslationConfiguration()
10270         {
10271                 return (!$this->_translateDefaultCulture && ($this->getDefaultCulture() == $this->getCulture()))
10272                         ? null
10273                         : $this->_translation;
10274         }
10275         protected function setTranslationConfiguration($config)
10276         {
10277                 if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
10278                 {
10279                         if($config['source'])
10280                         {
10281                                 $config['source'] = Prado::getPathOfNamespace($config['source']);
10282                                 if(!is_dir($config['source']))
10283                                 {
10284                                         if(@mkdir($config['source'])===false)
10285                                         throw new TConfigurationException('globalization_source_path_failed',
10286                                                 $config['source']);
10287                                         chmod($config['source'], PRADO_CHMOD);                          }
10288                         }
10289                         else
10290                         {
10291                                 throw new TConfigurationException("invalid source dir '{$config['source']}'");
10292                         }
10293                 }
10294                 if(isset($config['cache']) && TPropertyValue::ensureBoolean($config['cache']))
10295                 {
10296                         $config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
10297                         if(!is_dir($config['cache']))
10298                         {
10299                                 if(@mkdir($config['cache'])===false)
10300                                         throw new TConfigurationException('globalization_cache_path_failed',
10301                                                 $config['cache']);
10302                                 chmod($config['cache'], PRADO_CHMOD);                   }
10303                 }
10304                 else
10305                 {
10306                         unset($config['cache']);
10307                 }
10308                 $this->_translation = $config;
10309         }
10310         public function getTranslationCatalogue()
10311         {
10312                 return $this->_translation['catalogue'];
10313         }
10314         public function setTranslationCatalogue($value)
10315         {
10316                 $this->_translation['catalogue'] = $value;
10317         }
10318         public function getCultureVariants($culture=null)
10319         {
10320                 if($culture===null) $culture = $this->getCulture();
10321                 $variants = explode('_', $culture);
10322                 $result = array();
10323                 for(; count($variants) > 0; array_pop($variants))
10324                         $result[] = implode('_', $variants);
10325                 return $result;
10326         }
10327         public function getLocalizedResource($file,$culture=null)
10328         {
10329                 $files = array();
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'];
10337                 $files[] = $file;
10338                 return $files;
10339         }
10340 }
10341 class TApplication extends TComponent
10342 {
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(
10358                 'onBeginRequest',
10359                 'onLoadState',
10360                 'onLoadStateComplete',
10361                 'onAuthentication',
10362                 'onAuthenticationComplete',
10363                 'onAuthorization',
10364                 'onAuthorizationComplete',
10365                 'onPreRunService',
10366                 'runService',
10367                 'onSaveState',
10368                 'onSaveStateComplete',
10369                 'onPreFlushOutput',
10370                 'flushOutput'
10371         );
10372         private $_id;
10373         private $_uniqueID;
10374         private $_requestCompleted=false;
10375         private $_step;
10376         private $_services;
10377         private $_service;
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;
10390         private $_request;
10391         private $_response;
10392         private $_session;
10393         private $_cache;
10394         private $_statePersister;
10395         private $_user;
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)
10403         {
10404                                 Prado::setApplication($this);
10405                 $this->setConfigurationType($configType);
10406                 $this->resolvePaths($basePath);
10407                 if($cacheConfig)
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);
10413         }
10414         protected function resolvePaths($basePath)
10415         {
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))
10421                 {
10422                         $configFile=$basePath;
10423                         $basePath=dirname($configFile);
10424                 }
10425                 else
10426                         $configFile=null;
10427                                 $runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
10428                 if(is_writable($runtimePath))
10429                 {
10430                         if($configFile!==null)
10431                         {
10432                                 $runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
10433                                 if(!is_dir($runtimePath))
10434                                 {
10435                                         if(@mkdir($runtimePath)===false)
10436                                                 throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
10437                                         @chmod($runtimePath, PRADO_CHMOD);                              }
10438                                 $this->setConfigurationFile($configFile);
10439                         }
10440                         $this->setBasePath($basePath);
10441                         $this->setRuntimePath($runtimePath);
10442                 }
10443                 else
10444                         throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
10445         }
10446         public function run()
10447         {
10448                 try
10449                 {
10450                         $this->initApplication();
10451                         $n=count(self::$_steps);
10452                         $this->_step=0;
10453                         $this->_requestCompleted=false;
10454                         while($this->_step<$n)
10455                         {
10456                                 if($this->_mode===self::STATE_OFF)
10457                                         throw new THttpException(503,'application_unavailable');
10458                                 if($this->_requestCompleted)
10459                                         break;
10460                                 $method=self::$_steps[$this->_step];
10461                                 $this->$method();
10462                                 $this->_step++;
10463                         }
10464                 }
10465                 catch(Exception $e)
10466                 {
10467                         $this->onError($e);
10468                 }
10469                 $this->onEndRequest();
10470         }
10471         public function completeRequest()
10472         {
10473                 $this->_requestCompleted=true;
10474         }
10475         public function getRequestCompleted()
10476         {
10477                 return $this->_requestCompleted;
10478         }
10479         public function getGlobalState($key,$defaultValue=null)
10480         {
10481                 return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
10482         }
10483         public function setGlobalState($key,$value,$defaultValue=null,$forceSave=false)
10484         {
10485                 $this->_stateChanged=true;
10486                 if($value===$defaultValue)
10487                         unset($this->_globals[$key]);
10488                 else
10489                         $this->_globals[$key]=$value;
10490                 if($forceSave)
10491                         $this->saveGlobals();
10492         }
10493         public function clearGlobalState($key)
10494         {
10495                 $this->_stateChanged=true;
10496                 unset($this->_globals[$key]);
10497         }
10498         protected function loadGlobals()
10499         {
10500                 $this->_globals=$this->getApplicationStatePersister()->load();
10501         }
10502         protected function saveGlobals()
10503         {
10504                 if($this->_stateChanged)
10505                 {
10506                         $this->_stateChanged=false;
10507                         $this->getApplicationStatePersister()->save($this->_globals);
10508                 }
10509         }
10510         public function getID()
10511         {
10512                 return $this->_id;
10513         }
10514         public function setID($value)
10515         {
10516                 $this->_id=$value;
10517         }
10518         public function getPageServiceID()
10519         {
10520                 return $this->_pageServiceID;
10521         }
10522         public function setPageServiceID($value)
10523         {
10524                 $this->_pageServiceID=$value;
10525         }
10526         public function getUniqueID()
10527         {
10528                 return $this->_uniqueID;
10529         }
10530         public function getMode()
10531         {
10532                 return $this->_mode;
10533         }
10534         public function setMode($value)
10535         {
10536                 $this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
10537         }
10538         public function getBasePath()
10539         {
10540                 return $this->_basePath;
10541         }
10542         public function setBasePath($value)
10543         {
10544                 $this->_basePath=$value;
10545         }
10546         public function getConfigurationFile()
10547         {
10548                 return $this->_configFile;
10549         }
10550         public function setConfigurationFile($value)
10551         {
10552                 $this->_configFile=$value;
10553         }
10554         public function getConfigurationType()
10555         {
10556                 return $this->_configType;
10557         }
10558         public function setConfigurationType($value)
10559         {
10560                 $this->_configType = $value;
10561         }
10562         public function getConfigurationFileExt()
10563         {
10564                 if($this->_configFileExt===null)
10565                 {
10566                         switch($this->_configType)
10567                         {
10568                                 case TApplication::CONFIG_TYPE_PHP:
10569                                         $this->_configFileExt = TApplication::CONFIG_FILE_EXT_PHP;
10570                                         break;
10571                                 default:
10572                                         $this->_configFileExt = TApplication::CONFIG_FILE_EXT_XML;
10573                         }
10574                 }
10575                 return $this->_configFileExt;
10576         }
10577         public function getConfigurationFileName()
10578         {
10579                 static $fileName;
10580                 if($fileName == null)
10581                 {
10582                         switch($this->_configType)
10583                         {
10584                                 case TApplication::CONFIG_TYPE_PHP:
10585                                         $fileName = TApplication::CONFIG_FILE_PHP;
10586                                         break;
10587                                 default:
10588                                         $fileName = TApplication::CONFIG_FILE_XML;
10589                         }
10590                 }
10591                 return $fileName;
10592         }
10593         public function getRuntimePath()
10594         {
10595                 return $this->_runtimePath;
10596         }
10597         public function setRuntimePath($value)
10598         {
10599                 $this->_runtimePath=$value;
10600                 if($this->_cacheFile)
10601                         $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10602                                 $this->_uniqueID=md5($this->_runtimePath);
10603         }
10604         public function getService()
10605         {
10606                 return $this->_service;
10607         }
10608         public function setService($value)
10609         {
10610                 $this->_service=$value;
10611         }
10612         public function setModule($id,IModule $module=null)
10613         {
10614                 if(isset($this->_modules[$id]))
10615                         throw new TConfigurationException('application_moduleid_duplicated',$id);
10616                 else
10617                         $this->_modules[$id]=$module;
10618         }
10619         public function getModule($id)
10620         {
10621                 if(!array_key_exists($id, $this->_modules))
10622                         return null;
10623                                 if($this->_modules[$id]===null)
10624                 {
10625                         $module = $this->internalLoadModule($id, true);
10626                         $module[0]->init($module[1]);
10627                 }
10628                 return $this->_modules[$id];
10629         }
10630         public function getModules()
10631         {
10632                 return $this->_modules;
10633         }
10634         public function getParameters()
10635         {
10636                 return $this->_parameters;
10637         }
10638         public function getRequest()
10639         {
10640                 if(!$this->_request)
10641                 {
10642                         $this->_request=new THttpRequest;
10643                         $this->_request->init(null);
10644                 }
10645                 return $this->_request;
10646         }
10647         public function setRequest(THttpRequest $request)
10648         {
10649                 $this->_request=$request;
10650         }
10651         public function getResponse()
10652         {
10653                 if(!$this->_response)
10654                 {
10655                         $this->_response=new THttpResponse;
10656                         $this->_response->init(null);
10657                 }
10658                 return $this->_response;
10659         }
10660         public function setResponse(THttpResponse $response)
10661         {
10662                 $this->_response=$response;
10663         }
10664         public function getSession()
10665         {
10666                 if(!$this->_session)
10667                 {
10668                         $this->_session=new THttpSession;
10669                         $this->_session->init(null);
10670                 }
10671                 return $this->_session;
10672         }
10673         public function setSession(THttpSession $session)
10674         {
10675                 $this->_session=$session;
10676         }
10677         public function getErrorHandler()
10678         {
10679                 if(!$this->_errorHandler)
10680                 {
10681                         $this->_errorHandler=new TErrorHandler;
10682                         $this->_errorHandler->init(null);
10683                 }
10684                 return $this->_errorHandler;
10685         }
10686         public function setErrorHandler(TErrorHandler $handler)
10687         {
10688                 $this->_errorHandler=$handler;
10689         }
10690         public function getSecurityManager()
10691         {
10692                 if(!$this->_security)
10693                 {
10694                         $this->_security=new TSecurityManager;
10695                         $this->_security->init(null);
10696                 }
10697                 return $this->_security;
10698         }
10699         public function setSecurityManager(TSecurityManager $sm)
10700         {
10701                 $this->_security=$sm;
10702         }
10703         public function getAssetManager()
10704         {
10705                 if(!$this->_assetManager)
10706                 {
10707                         $this->_assetManager=new TAssetManager;
10708                         $this->_assetManager->init(null);
10709                 }
10710                 return $this->_assetManager;
10711         }
10712         public function setAssetManager(TAssetManager $value)
10713         {
10714                 $this->_assetManager=$value;
10715         }
10716         public function getApplicationStatePersister()
10717         {
10718                 if(!$this->_statePersister)
10719                 {
10720                         $this->_statePersister=new TApplicationStatePersister;
10721                         $this->_statePersister->init(null);
10722                 }
10723                 return $this->_statePersister;
10724         }
10725         public function setApplicationStatePersister(IStatePersister $persister)
10726         {
10727                 $this->_statePersister=$persister;
10728         }
10729         public function getCache()
10730         {
10731                 return $this->_cache;
10732         }
10733         public function setCache(ICache $cache)
10734         {
10735                 $this->_cache=$cache;
10736         }
10737         public function getUser()
10738         {
10739                 return $this->_user;
10740         }
10741         public function setUser(IUser $user)
10742         {
10743                 $this->_user=$user;
10744         }
10745         public function getGlobalization($createIfNotExists=true)
10746         {
10747                 if($this->_globalization===null && $createIfNotExists)
10748                 {
10749                         $this->_globalization=new TGlobalization;
10750                         $this->_globalization->init(null);
10751                 }
10752                 return $this->_globalization;
10753         }
10754         public function setGlobalization(TGlobalization $glob)
10755         {
10756                 $this->_globalization=$glob;
10757         }
10758         public function getAuthorizationRules()
10759         {
10760                 if($this->_authRules===null)
10761                         $this->_authRules=new TAuthorizationRuleCollection;
10762                 return $this->_authRules;
10763         }
10764         protected function getApplicationConfigurationClass()
10765         {
10766                 return 'TApplicationConfiguration';
10767         }
10768         protected function internalLoadModule($id, $force=false)
10769         {
10770                 list($moduleClass, $initProperties, $configElement)=$this->_lazyModules[$id];
10771                 if(isset($initProperties['lazy']) && $initProperties['lazy'] && !$force)
10772                 {
10773                         $this->setModule($id, null);
10774                         return null;
10775                 }
10776                 $module=Prado::createComponent($moduleClass);
10777                 foreach($initProperties as $name=>$value)
10778                 {
10779                         if($name==='lazy') continue;
10780                         $module->setSubProperty($name,$value);
10781                 }
10782                 $this->setModule($id,$module);
10783                                 $this->_lazyModules[$id]=null;
10784                 return array($module,$configElement);
10785         }
10786         public function applyConfiguration($config,$withinService=false)
10787         {
10788                 if($config->getIsEmpty())
10789                         return;
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)
10795                 {
10796                         foreach($config->getProperties() as $name=>$value)
10797                                 $this->setSubProperty($name,$value);
10798                 }
10799                 if(empty($this->_services))
10800                         $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10801                                 foreach($config->getParameters() as $id=>$parameter)
10802                 {
10803                         if(is_array($parameter))
10804                         {
10805                                 $component=Prado::createComponent($parameter[0]);
10806                                 foreach($parameter[1] as $name=>$value)
10807                                         $component->setSubProperty($name,$value);
10808                                 $this->_parameters->add($id,$component);
10809                         }
10810                         else
10811                                 $this->_parameters->add($id,$parameter);
10812                 }
10813                                 $modules=array();
10814                 foreach($config->getModules() as $id=>$moduleConfig)
10815                 {
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;
10821                 }
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)
10827                 {
10828                         if($condition!==true)
10829                                 $condition=$this->evaluateExpression($condition);
10830                         if($condition)
10831                         {
10832                                 if(($path=Prado::getPathOfNamespace($filePath,$this->getConfigurationFileExt()))===null || !is_file($path))
10833                                         throw new TConfigurationException('application_includefile_invalid',$filePath);
10834                                 $cn=$this->getApplicationConfigurationClass();
10835                                 $c=new $cn;
10836                                 $c->loadFromFile($path);
10837                                 $this->applyConfiguration($c,$withinService);
10838                         }
10839                 }
10840         }
10841         protected function initApplication()
10842         {
10843                 if($this->_configFile!==null)
10844                 {
10845                         if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
10846                         {
10847                                 $config=new TApplicationConfiguration;
10848                                 $config->loadFromFile($this->_configFile);
10849                                 if($this->_cacheFile!==null)
10850                                         file_put_contents($this->_cacheFile,serialize($config),LOCK_EX);
10851                         }
10852                         else
10853                                 $config=unserialize(file_get_contents($this->_cacheFile));
10854                         $this->applyConfiguration($config,false);
10855                 }
10856                 if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
10857                         $serviceID=$this->getPageServiceID();
10858                 $this->startService($serviceID);
10859         }
10860         public function startService($serviceID)
10861         {
10862                 if(isset($this->_services[$serviceID]))
10863                 {
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)
10875                         {
10876                                 $config=new TApplicationConfiguration;
10877                                 if($this->getConfigurationType()==self::CONFIG_TYPE_PHP)
10878                                         $config->loadFromPhp($configElement,$this->getBasePath());
10879                                 else
10880                                         $config->loadFromXml($configElement,$this->getBasePath());
10881                                 $this->applyConfiguration($config,true);
10882                         }
10883                         $service->init($configElement);
10884                 }
10885                 else
10886                         throw new THttpException(500,'application_service_unknown',$serviceID);
10887         }
10888         public function onError($param)
10889         {
10890                 Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
10891                 $this->raiseEvent('OnError',$this,$param);
10892                 $this->getErrorHandler()->handleError($this,$param);
10893         }
10894         public function onBeginRequest()
10895         {
10896                 $this->raiseEvent('OnBeginRequest',$this,null);
10897         }
10898         public function onAuthentication()
10899         {
10900                 $this->raiseEvent('OnAuthentication',$this,null);
10901         }
10902         public function onAuthenticationComplete()
10903         {
10904                 $this->raiseEvent('OnAuthenticationComplete',$this,null);
10905         }
10906         public function onAuthorization()
10907         {
10908                 $this->raiseEvent('OnAuthorization',$this,null);
10909         }
10910         public function onAuthorizationComplete()
10911         {
10912                 $this->raiseEvent('OnAuthorizationComplete',$this,null);
10913         }
10914         public function onLoadState()
10915         {
10916                 $this->loadGlobals();
10917                 $this->raiseEvent('OnLoadState',$this,null);
10918         }
10919         public function onLoadStateComplete()
10920         {
10921                 $this->raiseEvent('OnLoadStateComplete',$this,null);
10922         }
10923         public function onPreRunService()
10924         {
10925                 $this->raiseEvent('OnPreRunService',$this,null);
10926         }
10927         public function runService()
10928         {
10929                 if($this->_service)
10930                         $this->_service->run();
10931         }
10932         public function onSaveState()
10933         {
10934                 $this->raiseEvent('OnSaveState',$this,null);
10935                 $this->saveGlobals();
10936         }
10937         public function onSaveStateComplete()
10938         {
10939                 $this->raiseEvent('OnSaveStateComplete',$this,null);
10940         }
10941         public function onPreFlushOutput()
10942         {
10943                 $this->raiseEvent('OnPreFlushOutput',$this,null);
10944         }
10945         public function flushOutput($continueBuffering = true)
10946         {
10947                 $this->getResponse()->flush($continueBuffering);
10948         }
10949         public function onEndRequest()
10950         {
10951                 $this->flushOutput(false);              $this->saveGlobals();           $this->raiseEvent('OnEndRequest',$this,null);
10952         }
10953 }
10954 class TApplicationMode extends TEnumerable
10955 {
10956         const Off='Off';
10957         const Debug='Debug';
10958         const Normal='Normal';
10959         const Performance='Performance';
10960 }
10961 class TApplicationConfiguration extends TComponent
10962 {
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)
10972         {
10973                 if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10974                 {
10975                         $fcontent = include $fname;
10976                         $this->loadFromPhp($fcontent,dirname($fname));
10977                 }
10978                 else
10979                 {
10980                         $dom=new TXmlDocument;
10981                         $dom->loadFromFile($fname);
10982                         $this->loadFromXml($dom,dirname($fname));
10983                 }
10984         }
10985         public function getIsEmpty()
10986         {
10987                 return $this->_empty;
10988         }
10989         public function loadFromPhp($config, $configPath)
10990         {
10991                                 if(isset($config['application']))
10992                 {
10993                         foreach($config['application'] as $name=>$value)
10994                         {
10995                                 $this->_properties[$name]=$value;
10996                         }
10997                         $this->_empty = false;
10998                 }
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);
11009         }
11010         public function loadFromXml($dom,$configPath)
11011         {
11012                                 foreach($dom->getAttributes() as $name=>$value)
11013                 {
11014                         $this->_properties[$name]=$value;
11015                         $this->_empty=false;
11016                 }
11017                 foreach($dom->getElements() as $element)
11018                 {
11019                         switch($element->getTagName())
11020                         {
11021                                 case 'paths':
11022                                         $this->loadPathsXml($element,$configPath);
11023                                         break;
11024                                 case 'modules':
11025                                         $this->loadModulesXml($element,$configPath);
11026                                         break;
11027                                 case 'services':
11028                                         $this->loadServicesXml($element,$configPath);
11029                                         break;
11030                                 case 'parameters':
11031                                         $this->loadParametersXml($element,$configPath);
11032                                         break;
11033                                 case 'include':
11034                                         $this->loadExternalXml($element,$configPath);
11035                                         break;
11036                                 default:
11037                                                                                 break;
11038                         }
11039                 }
11040         }
11041         protected function loadPathsPhp($pathsNode, $configPath)
11042         {
11043                 if(isset($pathsNode['aliases']) && is_array($pathsNode['aliases']))
11044                 {
11045                         foreach($pathsNode['aliases'] as $id=>$path)
11046                         {
11047                                 $path=str_replace('\\','/',$path);
11048                                 if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))                                             $p=realpath($path);
11049                                 else
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;
11056                         }
11057                 }
11058                 if(isset($pathsNode['using']) && is_array($pathsNode['using']))
11059                 {
11060                         foreach($pathsNode['using'] as $namespace)
11061                         {
11062                                 $this->_usings[] = $namespace;
11063                         }
11064                 }
11065         }
11066         protected function loadPathsXml($pathsNode,$configPath)
11067         {
11068                 foreach($pathsNode->getElements() as $element)
11069                 {
11070                         switch($element->getTagName())
11071                         {
11072                                 case 'alias':
11073                                 {
11074                                         if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
11075                                         {
11076                                                 $path=str_replace('\\','/',$path);
11077                                                 if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))                                                             $p=realpath($path);
11078                                                 else
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;
11085                                         }
11086                                         else
11087                                                 throw new TConfigurationException('appconfig_alias_invalid');
11088                                         $this->_empty=false;
11089                                         break;
11090                                 }
11091                                 case 'using':
11092                                 {
11093                                         if(($namespace=$element->getAttribute('namespace'))!==null)
11094                                                 $this->_usings[]=$namespace;
11095                                         else
11096                                                 throw new TConfigurationException('appconfig_using_invalid');
11097                                         $this->_empty=false;
11098                                         break;
11099                                 }
11100                                 default:
11101                                         throw new TConfigurationException('appconfig_paths_invalid',$element->getTagName());
11102                         }
11103                 }
11104         }
11105         protected function loadModulesPhp($modulesNode, $configPath)
11106         {
11107                 foreach($modulesNode as $id=>$module)
11108                 {
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']))
11115                         {
11116                                 $properties = $module['properties'];
11117                                 unset($module['properties']);
11118                         }
11119                         $properties['id'] = $id;
11120                         $this->_modules[$id]=array($type,$properties,$module);
11121                         $this->_empty=false;
11122                 }
11123         }
11124         protected function loadModulesXml($modulesNode,$configPath)
11125         {
11126                 foreach($modulesNode->getElements() as $element)
11127                 {
11128                         if($element->getTagName()==='module')
11129                         {
11130                                 $properties=$element->getAttributes();
11131                                 $id=$properties->itemAt('id');
11132                                 $type=$properties->remove('class');
11133                                 if($type===null)
11134                                         throw new TConfigurationException('appconfig_moduletype_required',$id);
11135                                 $element->setParent(null);
11136                                 if($id===null)
11137                                         $this->_modules[]=array($type,$properties->toArray(),$element);
11138                                 else
11139                                         $this->_modules[$id]=array($type,$properties->toArray(),$element);
11140                                 $this->_empty=false;
11141                         }
11142                         else
11143                                 throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
11144                 }
11145         }
11146         protected function loadServicesPhp($servicesNode,$configPath)
11147         {
11148                 foreach($servicesNode as $id => $service)
11149                 {
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;
11158                 }
11159         }
11160         protected function loadServicesXml($servicesNode,$configPath)
11161         {
11162                 foreach($servicesNode->getElements() as $element)
11163                 {
11164                         if($element->getTagName()==='service')
11165                         {
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;
11174                         }
11175                         else
11176                                 throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
11177                 }
11178         }
11179         protected function loadParametersPhp($parametersNode,$configPath)
11180         {
11181                 foreach($parametersNode as $id => $parameter)
11182                 {
11183                         if(is_array($parameter))
11184                         {
11185                                 if(isset($parameter['class']))
11186                                 {
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);
11192                                 }
11193                         }
11194                         else
11195                         {
11196                                 $this->_parameters[$id] = $parameter;
11197                         }
11198                 }
11199         }
11200         protected function loadParametersXml($parametersNode,$configPath)
11201         {
11202                 foreach($parametersNode->getElements() as $element)
11203                 {
11204                         if($element->getTagName()==='parameter')
11205                         {
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)
11210                                 {
11211                                         if(($value=$properties->remove('value'))===null)
11212                                                 $this->_parameters[$id]=$element;
11213                                         else
11214                                                 $this->_parameters[$id]=$value;
11215                                 }
11216                                 else
11217                                         $this->_parameters[$id]=array($type,$properties->toArray());
11218                                 $this->_empty=false;
11219                         }
11220                         else
11221                                 throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
11222                 }
11223         }
11224         protected function loadExternalPhp($includeNode,$configPath)
11225         {
11226                 foreach($includeNode as $include)
11227                 {
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.')';
11234                         else
11235                                 $$this->_includes[$filePath]=$when;
11236                         $this->_empty=false;
11237                 }
11238         }
11239         protected function loadExternalXml($includeNode,$configPath)
11240         {
11241                 if(($when=$includeNode->getAttribute('when'))===null)
11242                         $when=true;
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.')';
11247                 else
11248                         $this->_includes[$filePath]=$when;
11249                 $this->_empty=false;
11250         }
11251         public function getProperties()
11252         {
11253                 return $this->_properties;
11254         }
11255         public function getAliases()
11256         {
11257                 return $this->_aliases;
11258         }
11259         public function getUsings()
11260         {
11261                 return $this->_usings;
11262         }
11263         public function getModules()
11264         {
11265                 return $this->_modules;
11266         }
11267         public function getServices()
11268         {
11269                 return $this->_services;
11270         }
11271         public function getParameters()
11272         {
11273                 return $this->_parameters;
11274         }
11275         public function getExternalConfigurations()
11276         {
11277                 return $this->_includes;
11278         }
11279 }
11280 class TApplicationStatePersister extends TModule implements IStatePersister
11281 {
11282         const CACHE_NAME='prado:appstate';
11283         public function init($config)
11284         {
11285                 $this->getApplication()->setApplicationStatePersister($this);
11286         }
11287         protected function getStateFilePath()
11288         {
11289                 return $this->getApplication()->getRuntimePath().'/global.cache';
11290         }
11291         public function load()
11292         {
11293                 if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
11294                         return unserialize($value);
11295                 else
11296                 {
11297                         if(($content=@file_get_contents($this->getStateFilePath()))!==false)
11298                                 return unserialize($content);
11299                         else
11300                                 return null;
11301                 }
11302         }
11303         public function save($state)
11304         {
11305                 $content=serialize($state);
11306                 $saveFile=true;
11307                 if(($cache=$this->getApplication()->getCache())!==null)
11308                 {
11309                         if($cache->get(self::CACHE_NAME)===$content)
11310                                 $saveFile=false;
11311                         else
11312                                 $cache->set(self::CACHE_NAME,$content);
11313                 }
11314                 if($saveFile)
11315                 {
11316                         $fileName=$this->getStateFilePath();
11317                         file_put_contents($fileName,$content,LOCK_EX);
11318                 }
11319         }
11320 }
11321 class TShellApplication extends TApplication
11322 {
11323         public function run()
11324         {
11325                 $this->initApplication();
11326         }
11327 }
11328 ?>