Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * File Name: pradolite.php
4
 * Last Update: 2009/01/11 20:12:48
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
	public static function getVersion()
26
	{
27
		return '3.1.4';
28
	}
29
	public static function initErrorHandlers()
30
	{
31
		set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting());
32
		set_exception_handler(array('PradoBase','exceptionHandler'));
33
	}
34
	public static function autoload($className)
35
	{
36
		include_once($className.self::CLASS_FILE_EXT);
37
		if(!class_exists($className,false) && !interface_exists($className,false))
38
			self::fatalError("Class file for '$className' cannot be found.");
39
	}
40
	public static function poweredByPrado($logoType=0)
41
	{
42
		$logoName=$logoType==1?'powered2':'powered';
43
		if(self::$_application!==null)
44
		{
45
			$am=self::$_application->getAssetManager();
46
			$url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
47
		}
48
		else
49
			$url='http://www.pradosoft.com/images/'.$logoName.'.gif';
50
		return '<a title="Powered by PRADO" href="http://www.pradosoft.com/" target="_blank"><img src="'.$url.'" style="border-width:0px;" alt="Powered by PRADO" /></a>';
51
	}
52
	public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
53
	{
54
		if(error_reporting()!=0)
55
			throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
56
	}
57
	public static function exceptionHandler($exception)
58
	{
59
		if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
60
		{
61
			$errorHandler->handleError(null,$exception);
62
		}
63
		else
64
		{
65
			echo $exception;
66
		}
67
		exit(1);
68
	}
69
	public static function setApplication($application)
70
	{
71
		if(self::$_application!==null)
72
			throw new TInvalidOperationException('prado_application_singleton_required');
73
		self::$_application=$application;
74
	}
75
	public static function getApplication()
76
	{
77
		return self::$_application;
78
	}
79
	public static function getFrameworkPath()
80
	{
81
		return PRADO_DIR;
82
	}
83
	public static function serialize($data)
84
	{
85
		$arr[0]=$data;
86
		return serialize($arr);
87
	}
88
	public static function unserialize($str)
89
	{
90
		$arr=unserialize($str);
91
		return isset($arr[0])?$arr[0]:null;
92
	}
93
	public static function createComponent($type)
94
	{
95
		self::using($type);
96
		if(($pos=strrpos($type,'.'))!==false)
97
			$type=substr($type,$pos+1);
98
		if(($n=func_num_args())>1)
99
		{
100
			$args=func_get_args();
101
			$s='$args[1]';
102
			for($i=2;$i<$n;++$i)
103
				$s.=",\$args[$i]";
104
			eval("\$component=new $type($s);");
105
			return $component;
106
		}
107
		else
108
			return new $type;
109
	}
110
	public static function using($namespace,$checkClassExistence=true)
111
	{
112
		if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
113
			return;
114
		if(($pos=strrpos($namespace,'.'))===false)  		{
115
			try
116
			{
117
				include_once($namespace.self::CLASS_FILE_EXT);
118
			}
119
			catch(Exception $e)
120
			{
121
				if($checkClassExistence && !class_exists($namespace,false))
122
					throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
123
				else
124
					throw $e;
125
			}
126
		}
127
		else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
128
		{
129
			$className=substr($namespace,$pos+1);
130
			if($className==='*')  			{
131
				self::$_usings[$namespace]=$path;
132
				set_include_path(get_include_path().PATH_SEPARATOR.$path);
133
			}
134
			else  			{
135
				self::$_usings[$namespace]=$path;
136
				if(!$checkClassExistence || !class_exists($className,false))
137
				{
138
					try
139
					{
140
						include_once($path);
141
					}
142
					catch(Exception $e)
143
					{
144
						if($checkClassExistence && !class_exists($className,false))
145
							throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
146
						else
147
							throw $e;
148
					}
149
				}
150
			}
151
		}
152
		else
153
			throw new TInvalidDataValueException('prado_using_invalid',$namespace);
154
	}
155
	public static function getPathOfNamespace($namespace,$ext='')
156
	{
157
		if(isset(self::$_usings[$namespace]))
158
			return self::$_usings[$namespace];
159
		else if(isset(self::$_aliases[$namespace]))
160
			return self::$_aliases[$namespace];
161
		else
162
		{
163
			$segs=explode('.',$namespace);
164
			$alias=array_shift($segs);
165
			if(($file=array_pop($segs))!==null && ($root=self::getPathOfAlias($alias))!==null)
166
				return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file==='*')?'':DIRECTORY_SEPARATOR.$file.$ext);
167
			else
168
				return null;
169
		}
170
	}
171
	public static function getPathOfAlias($alias)
172
	{
173
		return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
174
	}
175
	protected static function getPathAliases()
176
	{
177
		return self::$_aliases;
178
	}
179
	public static function setPathOfAlias($alias,$path)
180
	{
181
		if(isset(self::$_aliases[$alias]))
182
			throw new TInvalidOperationException('prado_alias_redefined',$alias);
183
		else if(($rp=realpath($path))!==false && is_dir($rp))
184
		{
185
			if(strpos($alias,'.')===false)
186
				self::$_aliases[$alias]=$rp;
187
			else
188
				throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
189
		}
190
		else
191
			throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
192
	}
193
	public static function fatalError($msg)
194
	{
195
		echo '<h1>Fatal Error</h1>';
196
		echo '<p>'.$msg.'</p>';
197
		if(!function_exists('debug_backtrace'))
198
			return;
199
		echo '<h2>Debug Backtrace</h2>';
200
		echo '<pre>';
201
		$index=-1;
202
		foreach(debug_backtrace() as $t)
203
		{
204
			$index++;
205
			if($index==0)  				continue;
206
			echo '#'.$index.' ';
207
			if(isset($t['file']))
208
				echo basename($t['file']) . ':' . $t['line'];
209
			else
210
			   echo '<PHP inner-code>';
211
			echo ' -- ';
212
			if(isset($t['class']))
213
				echo $t['class'] . $t['type'];
214
			echo $t['function'] . '(';
215
			if(isset($t['args']) && sizeof($t['args']) > 0)
216
			{
217
				$count=0;
218
				foreach($t['args'] as $item)
219
				{
220
					if(is_string($item))
221
					{
222
						$str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
223
						if (strlen($item) > 70)
224
							echo "'". substr($str, 0, 70) . "...'";
225
						else
226
							echo "'" . $str . "'";
227
					}
228
					else if (is_int($item) || is_float($item))
229
						echo $item;
230
					else if (is_object($item))
231
						echo get_class($item);
232
					else if (is_array($item))
233
						echo 'array(' . count($item) . ')';
234
					else if (is_bool($item))
235
						echo $item ? 'true' : 'false';
236
					else if ($item === null)
237
						echo 'NULL';
238
					else if (is_resource($item))
239
						echo get_resource_type($item);
240
					$count++;
241
					if (count($t['args']) > $count)
242
						echo ', ';
243
				}
244
			}
245
			echo ")\n";
246
		}
247
		echo '</pre>';
248
		exit(1);
249
	}
250
	public static function getUserLanguages()
251
	{
252
		static $languages=null;
253
		if($languages===null)
254
		{
255
			if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
256
				$languages[0]='en';
257
			else
258
			{
259
				$languages=array();
260
				foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
261
				{
262
					$array=split(';q=',trim($language));
263
					$languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
264
				}
265
				arsort($languages);
266
				$languages=array_keys($languages);
267
				if(empty($languages))
268
					$languages[0]='en';
269
			}
270
		}
271
		return $languages;
272
	}
273
	public static function getPreferredLanguage()
274
	{
275
		static $language=null;
276
		if($language===null)
277
		{
278
			$langs=Prado::getUserLanguages();
279
			$lang=explode('-',$langs[0]);
280
			if(empty($lang[0]) || !ctype_alpha($lang[0]))
281
				$language='en';
282
			else
283
				$language=$lang[0];
284
		}
285
		return $language;
286
	}
287
	public static function trace($msg,$category='Uncategorized')
288
	{
289
		if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
290
			return;
291
		if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
292
		{
293
			$trace=debug_backtrace();
294
			if(isset($trace[0]['file']) && isset($trace[0]['line']))
295
				$msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
296
			$level=TLogger::DEBUG;
297
		}
298
		else
299
			$level=TLogger::INFO;
300
		self::log($msg,$level,$category);
301
	}
302
	public static function log($msg,$level=TLogger::INFO,$category='Uncategorized')
303
	{
304
		if(self::$_logger===null)
305
			self::$_logger=new TLogger;
306
		self::$_logger->log($msg,$level,$category);
307
	}
308
	public static function getLogger()
309
	{
310
		if(self::$_logger===null)
311
			self::$_logger=new TLogger;
312
		return self::$_logger;
313
	}
314
	public static function varDump($var,$depth=10,$highlight=false)
315
	{
316
		Prado::using('System.Util.TVarDumper');
317
		return TVarDumper::dump($var,$depth,$highlight);
318
	}
319
	public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
320
	{
321
		Prado::using('System.I18N.Translation');
322
		$app = Prado::getApplication()->getGlobalization(false);
323
		$params = array();
324
		foreach($parameters as $key => $value)
325
			$params['{'.$key.'}'] = $value;
326
				if($app===null || ($config = $app->getTranslationConfiguration())===null)
327
			return strtr($text, $params);
328
		if ($catalogue===null)
329
			$catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
330
		Translation::init($catalogue);
331
				$appCharset = $app===null ? '' : $app->getCharset();
332
				$defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
333
				if(empty($charset)) $charset = $appCharset;
334
		if(empty($charset)) $charset = $defaultCharset;
335
		return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset);
336
	}
337
}
338
class TReflectionClass extends ReflectionClass
339
{
340
}
341
PradoBase::using('System.TComponent');
342
PradoBase::using('System.Exceptions.TException');
343
PradoBase::using('System.Util.TLogger');
344
if(!class_exists('Prado',false))
345
{
346
	class Prado extends PradoBase
347
	{
348
	}
349
}
350
spl_autoload_register(array('Prado','autoload'));
351
Prado::initErrorHandlers();
352
interface IModule
353
{
354
	public function init($config);
355
	public function getID();
356
	public function setID($id);
357
}
358
interface IService
359
{
360
	public function init($config);
361
	public function getID();
362
	public function setID($id);
363
	public function getEnabled();
364
	public function setEnabled($value);
365
	public function run();
366
}
367
interface ITextWriter
368
{
369
	public function write($str);
370
	public function flush();
371
}
372
interface IUser
373
{
374
	public function getName();
375
	public function setName($value);
376
	public function getIsGuest();
377
	public function setIsGuest($value);
378
	public function getRoles();
379
	public function setRoles($value);
380
	public function isInRole($role);
381
	public function saveToString();
382
	public function loadFromString($string);
383
}
384
interface IStatePersister
385
{
386
	public function load();
387
	public function save($state);
388
}
389
interface ICache
390
{
391
	public function get($id);
392
	public function set($id,$value,$expire=0,$dependency=null);
393
	public function add($id,$value,$expire=0,$dependency=null);
394
	public function delete($id);
395
	public function flush();
396
}
397
interface ICacheDependency
398
{
399
	public function getHasChanged();
400
}
401
interface IRenderable
402
{
403
	public function render($writer);
404
}
405
interface IBindable
406
{
407
	public function dataBind();
408
}
409
interface IStyleable
410
{
411
	public function getHasStyle();
412
	public function getStyle();
413
	public function clearStyle();
414
}
415
interface IActiveControl
416
{
417
	public function getActiveControl();
418
}
419
interface ICallbackEventHandler
420
{
421
	public function raiseCallbackEvent($eventArgument);
422
}
423
interface IDataRenderer
424
{
425
	public function getData();
426
	public function setData($value);
427
}
428
class TApplicationComponent extends TComponent
429
{
430
	public function getApplication()
431
	{
432
		return Prado::getApplication();
433
	}
434
	public function getService()
435
	{
436
		return Prado::getApplication()->getService();
437
	}
438
	public function getRequest()
439
	{
440
		return Prado::getApplication()->getRequest();
441
	}
442
	public function getResponse()
443
	{
444
		return Prado::getApplication()->getResponse();
445
	}
446
	public function getSession()
447
	{
448
		return Prado::getApplication()->getSession();
449
	}
450
	public function getUser()
451
	{
452
		return Prado::getApplication()->getUser();
453
	}
454
	public function publishAsset($assetPath,$className=null)
455
	{
456
		if($className===null)
457
			$className=get_class($this);
458
		$class=new ReflectionClass($className);
459
		$fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath;
460
		return $this->publishFilePath($fullPath);
461
	}
462
	public function publishFilePath($fullPath)
463
	{
464
		return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath);
465
	}
466
}
467
abstract class TModule extends TApplicationComponent implements IModule
468
{
469
	private $_id;
470
	public function init($config)
471
	{
472
	}
473
	public function getID()
474
	{
475
		return $this->_id;
476
	}
477
	public function setID($value)
478
	{
479
		$this->_id=$value;
480
	}
481
}
482
abstract class TService extends TApplicationComponent implements IService
483
{
484
	private $_id;
485
	private $_enabled=true;
486
	public function init($config)
487
	{
488
	}
489
	public function getID()
490
	{
491
		return $this->_id;
492
	}
493
	public function setID($value)
494
	{
495
		$this->_id=$value;
496
	}
497
	public function getEnabled()
498
	{
499
		return $this->_enabled;
500
	}
501
	public function setEnabled($value)
502
	{
503
		$this->_enabled=TPropertyValue::ensureBoolean($value);
504
	}
505
	public function run()
506
	{
507
	}
508
}
509
class TErrorHandler extends TModule
510
{
511
	const ERROR_FILE_NAME='error';
512
	const EXCEPTION_FILE_NAME='exception';
513
	const SOURCE_LINES=12;
514
	private $_templatePath=null;
515
	public function init($config)
516
	{
517
		$this->getApplication()->setErrorHandler($this);
518
	}
519
	public function getErrorTemplatePath()
520
	{
521
		if($this->_templatePath===null)
522
			$this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
523
		return $this->_templatePath;
524
	}
525
	public function setErrorTemplatePath($value)
526
	{
527
		if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath))
528
			$this->_templatePath=$templatePath;
529
		else
530
			throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value);
531
	}
532
	public function handleError($sender,$param)
533
	{
534
		static $handling=false;
535
		restore_error_handler();
536
		restore_exception_handler();
537
		if($handling)
538
			$this->handleRecursiveError($param);
539
		else
540
		{
541
			$handling=true;
542
			if(($response=$this->getResponse())!==null)
543
				$response->clear();
544
			if(!headers_sent())
545
				header('Content-Type: text/html; charset=UTF-8');
546
			if($param instanceof THttpException)
547
				$this->handleExternalError($param->getStatusCode(),$param);
548
			else if($this->getApplication()->getMode()===TApplicationMode::Debug)
549
				$this->displayException($param);
550
			else
551
				$this->handleExternalError(500,$param);
552
		}
553
	}
554
	protected function handleExternalError($statusCode,$exception)
555
	{
556
		if(!($exception instanceof THttpException))
557
			error_log($exception->__toString());
558
		$content=$this->getErrorTemplate($statusCode,$exception);
559
		$serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
560
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
561
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion();
562
		else
563
			$version='';
564
		$tokens=array(
565
			'%%StatusCode%%' => "$statusCode",
566
			'%%ErrorMessage%%' => htmlspecialchars($exception->getMessage()),
567
			'%%ServerAdmin%%' => $serverAdmin,
568
			'%%Version%%' => $version,
569
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
570
		);
571
		header("HTTP/1.0 $statusCode ".$exception->getMessage());
572
		echo strtr($content,$tokens);
573
	}
574
	protected function handleRecursiveError($exception)
575
	{
576
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
577
		{
578
			echo "<html><head><title>Recursive Error</title></head>\n";
579
			echo "<body><h1>Recursive Error</h1>\n";
580
			echo "<pre>".$exception->__toString()."</pre>\n";
581
			echo "</body></html>";
582
		}
583
		else
584
		{
585
			error_log("Error happened while processing an existing error:\n".$exception->__toString());
586
			header('HTTP/1.0 500 Internal Error');
587
		}
588
	}
589
	protected function displayException($exception)
590
	{
591
		if(php_sapi_name()==='cli')
592
		{
593
			echo $exception->getMessage()."\n";
594
			echo $exception->getTraceAsString();
595
			return;
596
		}
597
		if($exception instanceof TTemplateException)
598
		{
599
			$fileName=$exception->getTemplateFile();
600
			$lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
601
			$source=$this->getSourceCode($lines,$exception->getLineNumber());
602
			if($fileName==='')
603
				$fileName='---embedded template---';
604
			$errorLine=$exception->getLineNumber();
605
		}
606
		else
607
		{
608
			if(($trace=$this->getExactTrace($exception))!==null)
609
			{
610
				$fileName=$trace['file'];
611
				$errorLine=$trace['line'];
612
			}
613
			else
614
			{
615
				$fileName=$exception->getFile();
616
				$errorLine=$exception->getLine();
617
			}
618
			$source=$this->getSourceCode(@file($fileName),$errorLine);
619
		}
620
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
621
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion();
622
		else
623
			$version='';
624
		$tokens=array(
625
			'%%ErrorType%%' => get_class($exception),
626
			'%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
627
			'%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
628
			'%%SourceCode%%' => $source,
629
			'%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
630
			'%%Version%%' => $version,
631
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
632
		);
633
		$content=$this->getExceptionTemplate($exception);
634
		echo strtr($content,$tokens);
635
	}
636
	protected function getExceptionTemplate($exception)
637
	{
638
		$lang=Prado::getPreferredLanguage();
639
		$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html';
640
		if(!is_file($exceptionFile))
641
			$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html';
642
		if(($content=@file_get_contents($exceptionFile))===false)
643
			die("Unable to open exception template file '$exceptionFile'.");
644
		return $content;
645
	}
646
	protected function getErrorTemplate($statusCode,$exception)
647
	{
648
		$base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME;
649
		$lang=Prado::getPreferredLanguage();
650
		if(is_file("$base$statusCode-$lang.html"))
651
			$errorFile="$base$statusCode-$lang.html";
652
		else if(is_file("$base$statusCode.html"))
653
			$errorFile="$base$statusCode.html";
654
		else if(is_file("$base-$lang.html"))
655
			$errorFile="$base-$lang.html";
656
		else
657
			$errorFile="$base.html";
658
		if(($content=@file_get_contents($errorFile))===false)
659
			die("Unable to open error template file '$errorFile'.");
660
		return $content;
661
	}
662
	private function getExactTrace($exception)
663
	{
664
		$trace=$exception->getTrace();
665
		$result=null;
666
		if($exception instanceof TPhpErrorException)
667
			$result=isset($trace[0]['file'])?$trace[0]:$trace[1];
668
		else if($exception instanceof TInvalidOperationException)
669
		{
670
			if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
671
				$result=$this->getPropertyAccessTrace($trace,'__set');
672
		}
673
		if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
674
			return null;
675
		return $result;
676
	}
677
	private function getPropertyAccessTrace($trace,$pattern)
678
	{
679
		$result=null;
680
		foreach($trace as $t)
681
		{
682
			if(isset($t['function']) && $t['function']===$pattern)
683
				$result=$t;
684
			else
685
				break;
686
		}
687
		return $result;
688
	}
689
	private function getSourceCode($lines,$errorLine)
690
	{
691
		$beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
692
		$endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
693
		$source='';
694
		for($i=$beginLine;$i<$endLine;++$i)
695
		{
696
			if($i===$errorLine-1)
697
			{
698
				$line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
699
				$source.="<div class=\"error\">".$line."</div>";
700
			}
701
			else
702
				$source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
703
		}
704
		return $source;
705
	}
706
	private function addLink($message)
707
	{
708
		$baseUrl='http://www.pradosoft.com/docs/classdoc';
709
		return preg_replace('/\b(T[A-Z]\w+)\b/',"<a href=\"$baseUrl/\${1}\" target=\"_blank\">\${1}</a>",$message);
710
	}
711
}
712
class TList extends TComponent implements IteratorAggregate,ArrayAccess,Countable
713
{
714
	private $_d=array();
715
	private $_c=0;
716
	private $_r=false;
717
	public function __construct($data=null,$readOnly=false)
718
	{
719
		if($data!==null)
720
			$this->copyFrom($data);
721
		$this->setReadOnly($readOnly);
722
	}
723
	public function getReadOnly()
724
	{
725
		return $this->_r;
726
	}
727
	protected function setReadOnly($value)
728
	{
729
		$this->_r=TPropertyValue::ensureBoolean($value);
730
	}
731
	public function getIterator()
732
	{
733
		return new TListIterator($this->_d);
734
	}
735
	public function count()
736
	{
737
		return $this->getCount();
738
	}
739
	public function getCount()
740
	{
741
		return $this->_c;
742
	}
743
	public function itemAt($index)
744
	{
745
		if($index>=0 && $index<$this->_c)
746
			return $this->_d[$index];
747
		else
748
			throw new TInvalidDataValueException('list_index_invalid',$index);
749
	}
750
	public function add($item)
751
	{
752
		$this->insertAt($this->_c,$item);
753
		return $this->_c-1;
754
	}
755
	public function insertAt($index,$item)
756
	{
757
		if(!$this->_r)
758
		{
759
			if($index===$this->_c)
760
				$this->_d[$this->_c++]=$item;
761
			else if($index>=0 && $index<$this->_c)
762
			{
763
				array_splice($this->_d,$index,0,array($item));
764
				$this->_c++;
765
			}
766
			else
767
				throw new TInvalidDataValueException('list_index_invalid',$index);
768
		}
769
		else
770
			throw new TInvalidOperationException('list_readonly',get_class($this));
771
	}
772
	public function remove($item)
773
	{
774
		if(($index=$this->indexOf($item))>=0)
775
		{
776
			$this->removeAt($index);
777
			return $index;
778
		}
779
		else
780
			throw new TInvalidDataValueException('list_item_inexistent');
781
	}
782
	public function removeAt($index)
783
	{
784
		if(!$this->_r)
785
		{
786
			if($index>=0 && $index<$this->_c)
787
			{
788
				$this->_c--;
789
				if($index===$this->_c)
790
					return array_pop($this->_d);
791
				else
792
				{
793
					$item=$this->_d[$index];
794
					array_splice($this->_d,$index,1);
795
					return $item;
796
				}
797
			}
798
			else
799
				throw new TInvalidDataValueException('list_index_invalid',$index);
800
		}
801
		else
802
			throw new TInvalidOperationException('list_readonly',get_class($this));
803
	}
804
	public function clear()
805
	{
806
		for($i=$this->_c-1;$i>=0;--$i)
807
			$this->removeAt($i);
808
	}
809
	public function contains($item)
810
	{
811
		return $this->indexOf($item)>=0;
812
	}
813
	public function indexOf($item)
814
	{
815
		if(($index=array_search($item,$this->_d,true))===false)
816
			return -1;
817
		else
818
			return $index;
819
	}
820
	public function toArray()
821
	{
822
		return $this->_d;
823
	}
824
	public function copyFrom($data)
825
	{
826
		if(is_array($data) || ($data instanceof Traversable))
827
		{
828
			if($this->_c>0)
829
				$this->clear();
830
			foreach($data as $item)
831
				$this->add($item);
832
		}
833
		else if($data!==null)
834
			throw new TInvalidDataTypeException('list_data_not_iterable');
835
	}
836
	public function mergeWith($data)
837
	{
838
		if(is_array($data) || ($data instanceof Traversable))
839
		{
840
			foreach($data as $item)
841
				$this->add($item);
842
		}
843
		else if($data!==null)
844
			throw new TInvalidDataTypeException('list_data_not_iterable');
845
	}
846
	public function offsetExists($offset)
847
	{
848
		return ($offset>=0 && $offset<$this->_c);
849
	}
850
	public function offsetGet($offset)
851
	{
852
		return $this->itemAt($offset);
853
	}
854
	public function offsetSet($offset,$item)
855
	{
856
		if($offset===null || $offset===$this->_c)
857
			$this->insertAt($this->_c,$item);
858
		else
859
		{
860
			$this->removeAt($offset);
861
			$this->insertAt($offset,$item);
862
		}
863
	}
864
	public function offsetUnset($offset)
865
	{
866
		$this->removeAt($offset);
867
	}
868
}
869
class TListIterator implements Iterator
870
{
871
	private $_d;
872
	private $_i;
873
	private $_c;
874
	public function __construct(&$data)
875
	{
876
		$this->_d=&$data;
877
		$this->_i=0;
878
		$this->_c=count($this->_d);
879
	}
880
	public function rewind()
881
	{
882
		$this->_i=0;
883
	}
884
	public function key()
885
	{
886
		return $this->_i;
887
	}
888
	public function current()
889
	{
890
		return $this->_d[$this->_i];
891
	}
892
	public function next()
893
	{
894
		$this->_i++;
895
	}
896
	public function valid()
897
	{
898
		return $this->_i<$this->_c;
899
	}
900
}
901
abstract class TCache extends TModule implements ICache, ArrayAccess
902
{
903
	private $_prefix=null;
904
	private $_primary=true;
905
	public function init($config)
906
	{
907
		if($this->_prefix===null)
908
			$this->_prefix=$this->getApplication()->getUniqueID();
909
		if($this->_primary)
910
		{
911
			if($this->getApplication()->getCache()===null)
912
				$this->getApplication()->setCache($this);
913
			else
914
				throw new TConfigurationException('cache_primary_duplicated',get_class($this));
915
		}
916
	}
917
	public function getPrimaryCache()
918
	{
919
		return $this->_primary;
920
	}
921
	public function setPrimaryCache($value)
922
	{
923
		$this->_primary=TPropertyValue::ensureBoolean($value);
924
	}
925
	public function getKeyPrefix()
926
	{
927
		return $this->_prefix;
928
	}
929
	public function setKeyPrefix($value)
930
	{
931
		$this->_prefix=$value;
932
	}
933
	protected function generateUniqueKey($key)
934
	{
935
		return md5($this->_prefix.$key);
936
	}
937
	public function get($id)
938
	{
939
		if(($value=$this->getValue($this->generateUniqueKey($id)))!==false)
940
		{
941
			$data=unserialize($value);
942
			if(!is_array($data))
943
				return false;
944
			if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
945
				return $data[0];
946
		}
947
		return false;
948
	}
949
	public function set($id,$value,$expire=0,$dependency=null)
950
	{
951
		if(empty($value) && $expire === 0)
952
			$this->delete($id);
953
		else
954
		{
955
			$data=array($value,$dependency);
956
			return $this->setValue($this->generateUniqueKey($id),serialize($data),$expire);
957
		}
958
	}
959
	public function add($id,$value,$expire=0,$dependency=null)
960
	{
961
		if(empty($value) && $expire === 0)
962
			return false;
963
		$data=array($value,$dependency);
964
		return $this->addValue($this->generateUniqueKey($id),serialize($data),$expire);
965
	}
966
	public function delete($id)
967
	{
968
		return $this->deleteValue($this->generateUniqueKey($id));
969
	}
970
	public function flush()
971
	{
972
		throw new TNotSupportedException('cache_flush_unsupported');
973
	}
974
	abstract protected function getValue($key);
975
	abstract protected function setValue($key,$value,$expire);
976
	abstract protected function addValue($key,$value,$expire);
977
	abstract protected function deleteValue($key);
978
	public function offsetExists($id)
979
	{
980
		return $this->get($id) !== false;
981
	}
982
	public function offsetGet($id)
983
	{
984
		return $this->get($id);
985
	}
986
	public function offsetSet($id, $value)
987
	{
988
		$this->set($id, $value);
989
	}
990
	public function offsetUnset($id)
991
	{
992
		$this->delete($id);
993
	}
994
}
995
abstract class TCacheDependency extends TComponent implements ICacheDependency
996
{
997
}
998
class TFileCacheDependency extends TCacheDependency
999
{
1000
	private $_fileName;
1001
	private $_timestamp;
1002
	public function __construct($fileName)
1003
	{
1004
		$this->setFileName($fileName);
1005
	}
1006
	public function getFileName()
1007
	{
1008
		return $this->_fileName;
1009
	}
1010
	public function setFileName($value)
1011
	{
1012
		$this->_fileName=$value;
1013
		$this->_timestamp=@filemtime($value);
1014
	}
1015
	public function getTimestamp()
1016
	{
1017
		return $this->_timestamp;
1018
	}
1019
	public function getHasChanged()
1020
	{
1021
		return @filemtime($this->_fileName)!==$this->_timestamp;
1022
	}
1023
}
1024
class TDirectoryCacheDependency extends TCacheDependency
1025
{
1026
	private $_recursiveCheck=true;
1027
	private $_recursiveLevel=-1;
1028
	private $_timestamps;
1029
	private $_directory;
1030
	public function __construct($directory)
1031
	{
1032
		$this->setDirectory($directory);
1033
	}
1034
	public function getDirectory()
1035
	{
1036
		return $this->_directory;
1037
	}
1038
	public function setDirectory($directory)
1039
	{
1040
		if(($path=realpath($directory))===false || !is_dir($path))
1041
			throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
1042
		$this->_directory=$path;
1043
		$this->_timestamps=$this->generateTimestamps($path);
1044
	}
1045
	public function getRecursiveCheck()
1046
	{
1047
		return $this->_recursiveCheck;
1048
	}
1049
	public function setRecursiveCheck($value)
1050
	{
1051
		$this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
1052
	}
1053
	public function getRecursiveLevel()
1054
	{
1055
		return $this->_recursiveLevel;
1056
	}
1057
	public function setRecursiveLevel($value)
1058
	{
1059
		$this->_recursiveLevel=TPropertyValue::ensureInteger($value);
1060
	}
1061
	public function getHasChanged()
1062
	{
1063
		return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
1064
	}
1065
	protected function validateFile($fileName)
1066
	{
1067
		return true;
1068
	}
1069
	protected function validateDirectory($directory)
1070
	{
1071
		return true;
1072
	}
1073
	protected function generateTimestamps($directory,$level=0)
1074
	{
1075
		if(($dir=opendir($directory))===false)
1076
			throw new TIOException('directorycachedependency_directory_invalid',$directory);
1077
		$timestamps=array();
1078
		while(($file=readdir($dir))!==false)
1079
		{
1080
			$path=$directory.DIRECTORY_SEPARATOR.$file;
1081
			if($file==='.' || $file==='..')
1082
				continue;
1083
			else if(is_dir($path))
1084
			{
1085
				if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
1086
					$timestamps=array_merge($this->generateTimestamps($path,$level+1));
1087
			}
1088
			else if($this->validateFile($path))
1089
				$timestamps[$path]=filemtime($path);
1090
		}
1091
		closedir($dir);
1092
		return $timestamps;
1093
	}
1094
}
1095
class TGlobalStateCacheDependency extends TCacheDependency
1096
{
1097
	private $_stateName;
1098
	private $_stateValue;
1099
	public function __construct($name)
1100
	{
1101
		$this->setStateName($name);
1102
	}
1103
	public function getStateName()
1104
	{
1105
		return $this->_stateName;
1106
	}
1107
	public function setStateName($value)
1108
	{
1109
		$this->_stateName=$value;
1110
		$this->_stateValue=Prado::getApplication()->getGlobalState($value);
1111
	}
1112
	public function getHasChanged()
1113
	{
1114
		return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
1115
	}
1116
}
1117
class TChainedCacheDependency extends TCacheDependency
1118
{
1119
	private $_dependencies=null;
1120
	public function getDependencies()
1121
	{
1122
		if($this->_dependencies===null)
1123
			$this->_dependencies=new TCacheDependencyList;
1124
		return $this->_dependencies;
1125
	}
1126
	public function getHasChanged()
1127
	{
1128
		if($this->_dependencies!==null)
1129
		{
1130
			foreach($this->_dependencies as $dependency)
1131
				if($dependency->getHasChanged())
1132
					return true;
1133
		}
1134
		return false;
1135
	}
1136
}
1137
class TApplicationStateCacheDependency extends TCacheDependency
1138
{
1139
	public function getHasChanged()
1140
	{
1141
		return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
1142
	}
1143
}
1144
class TCacheDependencyList extends TList
1145
{
1146
	public function insertAt($index,$item)
1147
	{
1148
		if($item instanceof ICacheDependency)
1149
			parent::insertAt($index,$item);
1150
		else
1151
			throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
1152
	}
1153
}
1154
class TTextWriter extends TComponent implements ITextWriter
1155
{
1156
	private $_str='';
1157
	public function flush()
1158
	{
1159
		$str=$this->_str;
1160
		$this->_str='';
1161
		return $str;
1162
	}
1163
	public function write($str)
1164
	{
1165
		$this->_str.=$str;
1166
	}
1167
	public function writeLine($str='')
1168
	{
1169
		$this->write($str."\n");
1170
	}
1171
}
1172
class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable
1173
{
1174
	private $_d=array();
1175
	private $_r=false;
1176
	public function __construct($data=null,$readOnly=false)
1177
	{
1178
		if($data!==null)
1179
			$this->copyFrom($data);
1180
		$this->setReadOnly($readOnly);
1181
	}
1182
	public function getReadOnly()
1183
	{
1184
		return $this->_r;
1185
	}
1186
	protected function setReadOnly($value)
1187
	{
1188
		$this->_r=TPropertyValue::ensureBoolean($value);
1189
	}
1190
	public function getIterator()
1191
	{
1192
		return new TMapIterator($this->_d);
1193
	}
1194
	public function count()
1195
	{
1196
		return $this->getCount();
1197
	}
1198
	public function getCount()
1199
	{
1200
		return count($this->_d);
1201
	}
1202
	public function getKeys()
1203
	{
1204
		return array_keys($this->_d);
1205
	}
1206
	public function itemAt($key)
1207
	{
1208
		return isset($this->_d[$key]) ? $this->_d[$key] : null;
1209
	}
1210
	public function add($key,$value)
1211
	{
1212
		if(!$this->_r)
1213
			$this->_d[$key]=$value;
1214
		else
1215
			throw new TInvalidOperationException('map_readonly',get_class($this));
1216
	}
1217
	public function remove($key)
1218
	{
1219
		if(!$this->_r)
1220
		{
1221
			if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
1222
			{
1223
				$value=$this->_d[$key];
1224
				unset($this->_d[$key]);
1225
				return $value;
1226
			}
1227
			else
1228
				return null;
1229
		}
1230
		else
1231
			throw new TInvalidOperationException('map_readonly',get_class($this));
1232
	}
1233
	public function clear()
1234
	{
1235
		foreach(array_keys($this->_d) as $key)
1236
			$this->remove($key);
1237
	}
1238
	public function contains($key)
1239
	{
1240
		return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
1241
	}
1242
	public function toArray()
1243
	{
1244
		return $this->_d;
1245
	}
1246
	public function copyFrom($data)
1247
	{
1248
		if(is_array($data) || $data instanceof Traversable)
1249
		{
1250
			if($this->getCount()>0)
1251
				$this->clear();
1252
			foreach($data as $key=>$value)
1253
				$this->add($key,$value);
1254
		}
1255
		else if($data!==null)
1256
			throw new TInvalidDataTypeException('map_data_not_iterable');
1257
	}
1258
	public function mergeWith($data)
1259
	{
1260
		if(is_array($data) || $data instanceof Traversable)
1261
		{
1262
			foreach($data as $key=>$value)
1263
				$this->add($key,$value);
1264
		}
1265
		else if($data!==null)
1266
			throw new TInvalidDataTypeException('map_data_not_iterable');
1267
	}
1268
	public function offsetExists($offset)
1269
	{
1270
		return $this->contains($offset);
1271
	}
1272
	public function offsetGet($offset)
1273
	{
1274
		return $this->itemAt($offset);
1275
	}
1276
	public function offsetSet($offset,$item)
1277
	{
1278
		$this->add($offset,$item);
1279
	}
1280
	public function offsetUnset($offset)
1281
	{
1282
		$this->remove($offset);
1283
	}
1284
}
1285
class TMapIterator implements Iterator
1286
{
1287
	private $_d;
1288
	private $_keys;
1289
	private $_key;
1290
	public function __construct(&$data)
1291
	{
1292
		$this->_d=&$data;
1293
		$this->_keys=array_keys($data);
1294
	}
1295
	public function rewind()
1296
	{
1297
		$this->_key=reset($this->_keys);
1298
	}
1299
	public function key()
1300
	{
1301
		return $this->_key;
1302
	}
1303
	public function current()
1304
	{
1305
		return $this->_d[$this->_key];
1306
	}
1307
	public function next()
1308
	{
1309
		$this->_key=next($this->_keys);
1310
	}
1311
	public function valid()
1312
	{
1313
		return $this->_key!==false;
1314
	}
1315
}
1316
class TStack extends TComponent implements IteratorAggregate,Countable
1317
{
1318
	private $_d=array();
1319
	private $_c=0;
1320
	public function __construct($data=null)
1321
	{
1322
		if($data!==null)
1323
			$this->copyFrom($data);
1324
	}
1325
	public function toArray()
1326
	{
1327
		return $this->_d;
1328
	}
1329
	public function copyFrom($data)
1330
	{
1331
		if(is_array($data) || ($data instanceof Traversable))
1332
		{
1333
			$this->clear();
1334
			foreach($data as $item)
1335
			{
1336
				$this->_d[]=$item;
1337
				++$this->_c;
1338
			}
1339
		}
1340
		else if($data!==null)
1341
			throw new TInvalidDataTypeException('stack_data_not_iterable');
1342
	}
1343
	public function clear()
1344
	{
1345
		$this->_c=0;
1346
		$this->_d=array();
1347
	}
1348
	public function contains($item)
1349
	{
1350
		return array_search($item,$this->_d,true)!==false;
1351
	}
1352
	public function peek()
1353
	{
1354
		if($this->_c===0)
1355
			throw new TInvalidOperationException('stack_empty');
1356
		else
1357
			return $this->_d[$this->_c-1];
1358
	}
1359
	public function pop()
1360
	{
1361
		if($this->_c===0)
1362
			throw new TInvalidOperationException('stack_empty');
1363
		else
1364
		{
1365
			--$this->_c;
1366
			return array_pop($this->_d);
1367
		}
1368
	}
1369
	public function push($item)
1370
	{
1371
		++$this->_c;
1372
		array_push($this->_d,$item);
1373
	}
1374
	public function getIterator()
1375
	{
1376
		return new TStackIterator($this->_d);
1377
	}
1378
	public function getCount()
1379
	{
1380
		return $this->_c;
1381
	}
1382
	public function count()
1383
	{
1384
		return $this->getCount();
1385
	}
1386
}
1387
class TStackIterator implements Iterator
1388
{
1389
	private $_d;
1390
	private $_i;
1391
	private $_c;
1392
	public function __construct(&$data)
1393
	{
1394
		$this->_d=&$data;
1395
		$this->_i=0;
1396
		$this->_c=count($this->_d);
1397
	}
1398
	public function rewind()
1399
	{
1400
		$this->_i=0;
1401
	}
1402
	public function key()
1403
	{
1404
		return $this->_i;
1405
	}
1406
	public function current()
1407
	{
1408
		return $this->_d[$this->_i];
1409
	}
1410
	public function next()
1411
	{
1412
		$this->_i++;
1413
	}
1414
	public function valid()
1415
	{
1416
		return $this->_i<$this->_c;
1417
	}
1418
}
1419
class TXmlElement extends TComponent
1420
{
1421
	private $_parent=null;
1422
	private $_tagName='unknown';
1423
	private $_value='';
1424
	private $_elements=null;
1425
	private $_attributes=null;
1426
	public function __construct($tagName)
1427
	{
1428
		$this->setTagName($tagName);
1429
	}
1430
	public function getParent()
1431
	{
1432
		return $this->_parent;
1433
	}
1434
	public function setParent($parent)
1435
	{
1436
		$this->_parent=$parent;
1437
	}
1438
	public function getTagName()
1439
	{
1440
		return $this->_tagName;
1441
	}
1442
	public function setTagName($tagName)
1443
	{
1444
		$this->_tagName=$tagName;
1445
	}
1446
	public function getValue()
1447
	{
1448
		return $this->_value;
1449
	}
1450
	public function setValue($value)
1451
	{
1452
		$this->_value=$value;
1453
	}
1454
	public function getHasElement()
1455
	{
1456
		return $this->_elements!==null && $this->_elements->getCount()>0;
1457
	}
1458
	public function getHasAttribute()
1459
	{
1460
		return $this->_attributes!==null && $this->_attributes->getCount()>0;
1461
	}
1462
	public function getAttribute($name)
1463
	{
1464
		if($this->_attributes!==null)
1465
			return $this->_attributes->itemAt($name);
1466
		else
1467
			return null;
1468
	}
1469
	public function setAttribute($name,$value)
1470
	{
1471
		$this->getAttributes()->add($name,$value);
1472
	}
1473
	public function getElements()
1474
	{
1475
		if(!$this->_elements)
1476
			$this->_elements=new TXmlElementList($this);
1477
		return $this->_elements;
1478
	}
1479
	public function getAttributes()
1480
	{
1481
		if(!$this->_attributes)
1482
			$this->_attributes=new TMap;
1483
		return $this->_attributes;
1484
	}
1485
	public function getElementByTagName($tagName)
1486
	{
1487
		if($this->_elements)
1488
		{
1489
			foreach($this->_elements as $element)
1490
				if($element->_tagName===$tagName)
1491
					return $element;
1492
		}
1493
		return null;
1494
	}
1495
	public function getElementsByTagName($tagName)
1496
	{
1497
		$list=new TList;
1498
		if($this->_elements)
1499
		{
1500
			foreach($this->_elements as $element)
1501
				if($element->_tagName===$tagName)
1502
					$list->add($element);
1503
		}
1504
		return $list;
1505
	}
1506
	public function toString($indent=0)
1507
	{
1508
		$attr='';
1509
		if($this->_attributes!==null)
1510
		{
1511
			foreach($this->_attributes as $name=>$value)
1512
			{
1513
				$value=$this->xmlEncode($value);
1514
				$attr.=" $name=\"$value\"";
1515
			}
1516
		}
1517
		$prefix=str_repeat(' ',$indent*4);
1518
		if($this->getHasElement())
1519
		{
1520
			$str=$prefix."<{$this->_tagName}$attr>\n";
1521
			foreach($this->getElements() as $element)
1522
				$str.=$element->toString($indent+1)."\n";
1523
			$str.=$prefix."</{$this->_tagName}>";
1524
			return $str;
1525
		}
1526
		else if(($value=$this->getValue())!=='')
1527
		{
1528
			$value=$this->xmlEncode($value);
1529
			return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>";
1530
		}
1531
		else
1532
			return $prefix."<{$this->_tagName}$attr />";
1533
	}
1534
	public function __toString()
1535
	{
1536
		return $this->toString();
1537
	}
1538
	private function xmlEncode($str)
1539
	{
1540
		return strtr($str,array(
1541
			'>'=>'&gt;',
1542
			'<'=>'&lt;',
1543
			'&'=>'&amp;',
1544
			'"'=>'&quot;',
1545
			"\r"=>'&#xD;',
1546
			"\t"=>'&#x9;',
1547
			"\n"=>'&#xA;'));
1548
	}
1549
}
1550
class TXmlDocument extends TXmlElement
1551
{
1552
	private $_version;
1553
	private $_encoding;
1554
	public function __construct($version='1.0',$encoding='')
1555
	{
1556
		parent::__construct('');
1557
		$this->setVersion($version);
1558
		$this->setEncoding($encoding);
1559
	}
1560
	public function getVersion()
1561
	{
1562
		return $this->_version;
1563
	}
1564
	public function setVersion($version)
1565
	{
1566
		$this->_version=$version;
1567
	}
1568
	public function getEncoding()
1569
	{
1570
		return $this->_encoding;
1571
	}
1572
	public function setEncoding($encoding)
1573
	{
1574
		$this->_encoding=$encoding;
1575
	}
1576
	public function loadFromFile($file)
1577
	{
1578
		if(($str=@file_get_contents($file))!==false)
1579
			return $this->loadFromString($str);
1580
		else
1581
			throw new TIOException('xmldocument_file_read_failed',$file);
1582
	}
1583
	public function loadFromString($string)
1584
	{
1585
				$doc=new DOMDocument();
1586
		if($doc->loadXML($string)===false)
1587
			return false;
1588
		$this->setEncoding($doc->encoding);
1589
		$this->setVersion($doc->version);
1590
		$element=$doc->documentElement;
1591
		$this->setTagName($element->tagName);
1592
		$this->setValue($element->nodeValue);
1593
		$elements=$this->getElements();
1594
		$attributes=$this->getAttributes();
1595
		$elements->clear();
1596
		$attributes->clear();
1597
		foreach($element->attributes as $name=>$attr)
1598
			$attributes->add($name,$attr->value);
1599
		foreach($element->childNodes as $child)
1600
		{
1601
			if($child instanceof DOMElement)
1602
				$elements->add($this->buildElement($child));
1603
		}
1604
		return true;
1605
	}
1606
	public function saveToFile($file)
1607
	{
1608
		if(($fw=fopen($file,'w'))!==false)
1609
		{
1610
			fwrite($fw,$this->saveToString());
1611
			fclose($fw);
1612
		}
1613
		else
1614
			throw new TIOException('xmldocument_file_write_failed',$file);
1615
	}
1616
	public function saveToString()
1617
	{
1618
		$version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
1619
		$encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
1620
		return "<?xml{$version}{$encoding}?>\n".$this->toString(0);
1621
	}
1622
	public function __toString()
1623
	{
1624
		return $this->saveToString();
1625
	}
1626
	private function buildElement($node)
1627
	{
1628
		$element=new TXmlElement($node->tagName);
1629
		$element->setValue($node->nodeValue);
1630
		foreach($node->attributes as $name=>$attr)
1631
			$element->getAttributes()->add($name,$attr->value);
1632
		foreach($node->childNodes as $child)
1633
		{
1634
			if($child instanceof DOMElement)
1635
				$element->getElements()->add($this->buildElement($child));
1636
		}
1637
		return $element;
1638
	}
1639
}
1640
class TXmlElementList extends TList
1641
{
1642
	private $_o;
1643
	public function __construct(TXmlElement $owner)
1644
	{
1645
		$this->_o=$owner;
1646
	}
1647
	protected function getOwner()
1648
	{
1649
		return $this->_o;
1650
	}
1651
	public function insertAt($index,$item)
1652
	{
1653
		if($item instanceof TXmlElement)
1654
		{
1655
			parent::insertAt($index,$item);
1656
			if($item->getParent()!==null)
1657
				$item->getParent()->getElements()->remove($item);
1658
			$item->setParent($this->_o);
1659
		}
1660
		else
1661
			throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
1662
	}
1663
	public function removeAt($index)
1664
	{
1665
		$item=parent::removeAt($index);
1666
		if($item instanceof TXmlElement)
1667
			$item->setParent(null);
1668
		return $item;
1669
	}
1670
}
1671
class TAuthorizationRule extends TComponent
1672
{
1673
	private $_action;
1674
	private $_users;
1675
	private $_roles;
1676
	private $_verb;
1677
	private $_ipRules;
1678
	private $_everyone;
1679
	private $_guest;
1680
	private $_authenticated;
1681
	public function __construct($action,$users,$roles,$verb='',$ipRules='')
1682
	{
1683
		$action=strtolower(trim($action));
1684
		if($action==='allow' || $action==='deny')
1685
			$this->_action=$action;
1686
		else
1687
			throw new TInvalidDataValueException('authorizationrule_action_invalid',$action);
1688
		$this->_users=array();
1689
		$this->_roles=array();
1690
		$this->_ipRules=array();
1691
		$this->_everyone=false;
1692
		$this->_guest=false;
1693
		$this->_authenticated=false;
1694
		if(trim($users)==='')
1695
			$users='*';
1696
		foreach(explode(',',$users) as $user)
1697
		{
1698
			if(($user=trim(strtolower($user)))!=='')
1699
			{
1700
				if($user==='*')
1701
				{
1702
					$this->_everyone=true;
1703
					break;
1704
				}
1705
				else if($user==='?')
1706
					$this->_guest=true;
1707
				else if($user==='@')
1708
					$this->_authenticated=true;
1709
				else
1710
					$this->_users[]=$user;
1711
			}
1712
		}
1713
		if(trim($roles)==='')
1714
			$roles='*';
1715
		foreach(explode(',',$roles) as $role)
1716
		{
1717
			if(($role=trim(strtolower($role)))!=='')
1718
				$this->_roles[]=$role;
1719
		}
1720
		if(($verb=trim(strtolower($verb)))==='')
1721
			$verb='*';
1722
		if($verb==='*' || $verb==='get' || $verb==='post')
1723
			$this->_verb=$verb;
1724
		else
1725
			throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb);
1726
		if(trim($ipRules)==='')
1727
			$ipRules='*';
1728
		foreach(explode(',',$ipRules) as $ipRule)
1729
		{
1730
			if(($ipRule=trim($ipRule))!=='')
1731
				$this->_ipRules[]=$ipRule;
1732
		}
1733
	}
1734
	public function getAction()
1735
	{
1736
		return $this->_action;
1737
	}
1738
	public function getUsers()
1739
	{
1740
		return $this->_users;
1741
	}
1742
	public function getRoles()
1743
	{
1744
		return $this->_roles;
1745
	}
1746
	public function getVerb()
1747
	{
1748
		return $this->_verb;
1749
	}
1750
	public function getIPRules()
1751
	{
1752
		return $this->_ipRules;
1753
	}
1754
	public function getGuestApplied()
1755
	{
1756
		return $this->_guest || $this->_everyone;
1757
	}
1758
	public function getEveryoneApplied()
1759
	{
1760
		return $this->_everyone;
1761
	}
1762
	public function getAuthenticatedApplied()
1763
	{
1764
		return $this->_authenticated || $this->_everyone;
1765
	}
1766
	public function isUserAllowed(IUser $user,$verb,$ip)
1767
	{
1768
		if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user))
1769
			return ($this->_action==='allow')?1:-1;
1770
		else
1771
			return 0;
1772
	}
1773
	private function isIpMatched($ip)
1774
	{
1775
		if(empty($this->_ipRules))
1776
			return 1;
1777
		foreach($this->_ipRules as $rule)
1778
		{
1779
			if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0))
1780
				return 1;
1781
		}
1782
		return 0;
1783
	}
1784
	private function isUserMatched($user)
1785
	{
1786
		return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users));
1787
	}
1788
	private function isRoleMatched($user)
1789
	{
1790
		foreach($this->_roles as $role)
1791
		{
1792
			if($role==='*' || $user->isInRole($role))
1793
				return true;
1794
		}
1795
		return false;
1796
	}
1797
	private function isVerbMatched($verb)
1798
	{
1799
		return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0);
1800
	}
1801
}
1802
class TAuthorizationRuleCollection extends TList
1803
{
1804
	public function isUserAllowed($user,$verb,$ip)
1805
	{
1806
		if($user instanceof IUser)
1807
		{
1808
			$verb=strtolower(trim($verb));
1809
			foreach($this as $rule)
1810
			{
1811
				if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0)
1812
					return ($decision>0);
1813
			}
1814
			return true;
1815
		}
1816
		else
1817
			return false;
1818
	}
1819
	public function insertAt($index,$item)
1820
	{
1821
		if($item instanceof TAuthorizationRule)
1822
			parent::insertAt($index,$item);
1823
		else
1824
			throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required');
1825
	}
1826
}
1827
class TSecurityManager extends TModule
1828
{
1829
	const STATE_VALIDATION_KEY='prado:securitymanager:validationkey';
1830
	const STATE_ENCRYPTION_KEY='prado:securitymanager:encryptionkey';
1831
	private $_validationKey=null;
1832
	private $_encryptionKey=null;
1833
	private $_validation=TSecurityManagerValidationMode::SHA1;
1834
	private $_encryption='3DES';
1835
	public function init($config)
1836
	{
1837
		$this->getApplication()->setSecurityManager($this);
1838
	}
1839
	protected function generateRandomKey()
1840
	{
1841
		return rand().rand().rand().rand();
1842
	}
1843
	public function getValidationKey()
1844
	{
1845
		if($this->_validationKey===null)
1846
		{
1847
			if(($this->_validationKey=$this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))===null)
1848
			{
1849
				$this->_validationKey=$this->generateRandomKey();
1850
				$this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY,$this->_validationKey,null);
1851
			}
1852
		}
1853
		return $this->_validationKey;
1854
	}
1855
	public function setValidationKey($value)
1856
	{
1857
		if($value!=='')
1858
			$this->_validationKey=$value;
1859
		else
1860
			throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
1861
	}
1862
	public function getEncryptionKey()
1863
	{
1864
		if($this->_encryptionKey===null)
1865
		{
1866
			if(($this->_encryptionKey=$this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))===null)
1867
			{
1868
				$this->_encryptionKey=$this->generateRandomKey();
1869
				$this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY,$this->_encryptionKey,null);
1870
			}
1871
		}
1872
		return $this->_encryptionKey;
1873
	}
1874
	public function setEncryptionKey($value)
1875
	{
1876
		if($value!=='')
1877
			$this->_encryptionKey=$value;
1878
		else
1879
			throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
1880
	}
1881
	public function getValidation()
1882
	{
1883
		return $this->_validation;
1884
	}
1885
	public function setValidation($value)
1886
	{
1887
		$this->_validation=TPropertyValue::ensureEnum($value,'TSecurityManagerValidationMode');
1888
	}
1889
	public function getEncryption()
1890
	{
1891
		return $this->_encryption;
1892
	}
1893
	public function setEncryption($value)
1894
	{
1895
		throw new TNotSupportedException('Currently only 3DES encryption is supported');
1896
	}
1897
	public function encrypt($data)
1898
	{
1899
		if(function_exists('mcrypt_encrypt'))
1900
		{
1901
			$module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
1902
			$key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module));
1903
			srand();
1904
			$iv=mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
1905
			mcrypt_generic_init($module,$key,$iv);
1906
			$encrypted=$iv.mcrypt_generic($module,$data);
1907
			mcrypt_generic_deinit($module);
1908
			mcrypt_module_close($module);
1909
			return $encrypted;
1910
		}
1911
		else
1912
			throw new TNotSupportedException('securitymanager_mcryptextension_required');
1913
	}
1914
	public function decrypt($data)
1915
	{
1916
		if(function_exists('mcrypt_decrypt'))
1917
		{
1918
			$module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
1919
			$key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module));
1920
			$ivSize=mcrypt_enc_get_iv_size($module);
1921
			$iv=substr($data,0,$ivSize);
1922
			mcrypt_generic_init($module,$key,$iv);
1923
			$decrypted=mdecrypt_generic($module,substr($data,$ivSize));
1924
			mcrypt_generic_deinit($module);
1925
			mcrypt_module_close($module);
1926
			return rtrim($decrypted,"\0");
1927
		}
1928
		else
1929
			throw new TNotSupportedException('securitymanager_mcryptextension_required');
1930
	}
1931
	public function hashData($data)
1932
	{
1933
		$hmac=$this->computeHMAC($data);
1934
		return $hmac.$data;
1935
	}
1936
	public function validateData($data)
1937
	{
1938
		$len=$this->_validation==='SHA1'?40:32;
1939
		if(strlen($data)>=$len)
1940
		{
1941
			$hmac=substr($data,0,$len);
1942
			$data2=substr($data,$len);
1943
			return $hmac===$this->computeHMAC($data2)?$data2:false;
1944
		}
1945
		else
1946
			return false;
1947
	}
1948
	protected function computeHMAC($data)
1949
	{
1950
		if($this->_validation==='SHA1')
1951
		{
1952
			$pack='H40';
1953
			$func='sha1';
1954
		}
1955
		else
1956
		{
1957
			$pack='H32';
1958
			$func='md5';
1959
		}
1960
		$key=$this->getValidationKey();
1961
		$key=str_pad($func($key), 64, chr(0));
1962
		return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
1963
	}
1964
}
1965
class TSecurityManagerValidationMode extends TEnumerable
1966
{
1967
	const MD5='MD5';
1968
	const SHA1='SHA1';
1969
}
1970
class THttpUtility
1971
{
1972
	private static $_encodeTable=array('<'=>'&lt;','>'=>'&gt;','"'=>'&quot;');
1973
	private static $_decodeTable=array('&lt;'=>'<','&gt;'=>'>','&quot;'=>'"');
1974
	public static function htmlEncode($s)
1975
	{
1976
		return strtr($s,self::$_encodeTable);
1977
	}
1978
	public static function htmlDecode($s)
1979
	{
1980
		return strtr($s,self::$_decodeTable);
1981
	}
1982
}
1983
class TJavaScript
1984
{
1985
	private static $_json;
1986
	public static function renderScriptFiles($files)
1987
	{
1988
		$str='';
1989
		foreach($files as $file)
1990
			$str.= self::renderScriptFile($file);
1991
		return $str;
1992
	}
1993
	public static function renderScriptFile($file)
1994
	{
1995
		return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
1996
	}
1997
	public static function renderScriptBlocks($scripts)
1998
	{
1999
		if(count($scripts))
2000
			return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
2001
		else
2002
			return '';
2003
	}
2004
	public static function renderScriptBlock($script)
2005
	{
2006
		return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
2007
	}
2008
	public static function quoteString($js,$forUrl=false)
2009
	{
2010
		if($forUrl)
2011
			return strtr($js,array('%'=>'%25',"\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
2012
		else
2013
			return strtr($js,array("\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
2014
	}
2015
	public static function quoteFunction($js)
2016
	{
2017
		if(self::isFunction($js))
2018
			return $js;
2019
		else
2020
			return 'javascript:'.$js;
2021
	}
2022
	public static function isFunction($js)
2023
	{
2024
		return preg_match('/^\s*javascript:/i', $js);
2025
	}
2026
	public static function encode($value,$toMap=true)
2027
	{
2028
		if(is_string($value))
2029
		{
2030
			if(($n=strlen($value))>2)
2031
			{
2032
				$first=$value[0];
2033
				$last=$value[$n-1];
2034
				if(($first==='[' && $last===']') || ($first==='{' && $last==='}'))
2035
					return $value;
2036
			}
2037
			if(self::isFunction($value))
2038
				return preg_replace('/^\s*javascript:/', '', $value);
2039
			else
2040
				return "'".self::quoteString($value)."'";
2041
		}
2042
		else if(is_bool($value))
2043
			return $value?'true':'false';
2044
		else if(is_array($value))
2045
		{
2046
			$results='';
2047
			if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
2048
			{
2049
				foreach($value as $k=>$v)
2050
				{
2051
					if($v!=='')
2052
					{
2053
						if($results!=='')
2054
							$results.=',';
2055
						$results.="'$k':".self::encode($v,$toMap);
2056
					}
2057
				}
2058
				return '{'.$results.'}';
2059
			}
2060
			else
2061
			{
2062
				foreach($value as $v)
2063
				{
2064
					if($v!=='')
2065
					{
2066
						if($results!=='')
2067
							$results.=',';
2068
						$results.=self::encode($v,$toMap);
2069
					}
2070
				}
2071
				return '['.$results.']';
2072
			}
2073
		}
2074
		else if(is_integer($value))
2075
			return "$value";
2076
		else if(is_float($value))
2077
		{
2078
			if($value===-INF)
2079
				return 'Number.NEGATIVE_INFINITY';
2080
			else if($value===INF)
2081
				return 'Number.POSITIVE_INFINITY';
2082
			else
2083
				return "$value";
2084
		}
2085
		else if(is_object($value))
2086
			return self::encode(get_object_vars($value),$toMap);
2087
		else if($value===null)
2088
			return 'null';
2089
		else
2090
			return '';
2091
	}
2092
	public static function jsonEncode($value)
2093
	{
2094
		if(self::$_json === null)
2095
			self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON');
2096
		return self::$_json->encode($value);
2097
	}
2098
	public static function jsonDecode($value)
2099
	{
2100
		if(self::$_json === null)
2101
			self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON');
2102
		return self::$_json->decode($value);
2103
	}
2104
}
2105
class TUrlManager extends TModule
2106
{
2107
	public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
2108
	{
2109
		$url=$serviceID.'='.urlencode($serviceParam);
2110
		$amp=$encodeAmpersand?'&amp;':'&';
2111
		$request=$this->getRequest();
2112
		if(is_array($getItems) || $getItems instanceof Traversable)
2113
		{
2114
			if($encodeGetItems)
2115
			{
2116
				foreach($getItems as $name=>$value)
2117
				{
2118
					if(is_array($value))
2119
					{
2120
						$name=urlencode($name.'[]');
2121
						foreach($value as $v)
2122
							$url.=$amp.$name.'='.urlencode($v);
2123
					}
2124
					else
2125
						$url.=$amp.urlencode($name).'='.urlencode($value);
2126
				}
2127
			}
2128
			else
2129
			{
2130
				foreach($getItems as $name=>$value)
2131
				{
2132
					if(is_array($value))
2133
					{
2134
						foreach($value as $v)
2135
							$url.=$amp.$name.'[]='.$v;
2136
					}
2137
					else
2138
						$url.=$amp.$name.'='.$value;
2139
				}
2140
			}
2141
		}
2142
		if($request->getUrlFormat()===THttpRequestUrlFormat::Path)
2143
			return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
2144
		else
2145
			return $request->getApplicationUrl().'?'.$url;
2146
	}
2147
	public function parseUrl()
2148
	{
2149
		$request=$this->getRequest();
2150
		$pathInfo=trim($request->getPathInfo(),'/');
2151
		if($request->getUrlFormat()===THttpRequestUrlFormat::Path && $pathInfo!=='')
2152
		{
2153
			$separator=$request->getUrlParamSeparator();
2154
			$paths=explode('/',$pathInfo);
2155
			$getVariables=array();
2156
			foreach($paths as $path)
2157
			{
2158
				if(($path=trim($path))!=='')
2159
				{
2160
					if(($pos=strpos($path,$separator))!==false)
2161
					{
2162
						$name=substr($path,0,$pos);
2163
						$value=substr($path,$pos+1);
2164
						if(($pos=strpos($name,'[]'))!==false)
2165
							$getVariables[substr($name,0,$pos)][]=$value;
2166
						else
2167
							$getVariables[$name]=$value;
2168
					}
2169
					else
2170
						$getVariables[$path]='';
2171
				}
2172
			}
2173
			return $getVariables;
2174
		}
2175
		else
2176
			return array();
2177
	}
2178
}
2179
class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
2180
{
2181
	private $_urlManager=null;
2182
	private $_urlManagerID='';
2183
	private $_separator=',';
2184
	private $_serviceID=null;
2185
	private $_serviceParam=null;
2186
	private $_cookies=null;
2187
	private $_requestUri;
2188
	private $_pathInfo;
2189
	private $_cookieOnly=false;
2190
	private $_urlFormat=THttpRequestUrlFormat::Get;
2191
	private $_services;
2192
	private $_requestResolved=false;
2193
	private $_enableCookieValidation=false;
2194
	private $_url=null;
2195
	private $_id;
2196
	private $_items=array();
2197
	public function getID()
2198
	{
2199
		return $this->_id;
2200
	}
2201
	public function setID($value)
2202
	{
2203
		$this->_id=$value;
2204
	}
2205
	public function init($config)
2206
	{
2207
		if(empty($this->_urlManagerID))
2208
		{
2209
			$this->_urlManager=new TUrlManager;
2210
			$this->_urlManager->init(null);
2211
		}
2212
		else
2213
		{
2214
			$this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
2215
			if($this->_urlManager===null)
2216
				throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
2217
			if(!($this->_urlManager instanceof TUrlManager))
2218
				throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
2219
		}
2220
				if(php_sapi_name()==='cli')
2221
		{
2222
			$_SERVER['REMOTE_ADDR']='127.0.0.1';
2223
			$_SERVER['REQUEST_METHOD']='GET';
2224
			$_SERVER['SERVER_NAME']='localhost';
2225
			$_SERVER['SERVER_PORT']=80;
2226
			$_SERVER['HTTP_USER_AGENT']='';
2227
		}
2228
		$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
2229
														if(isset($_SERVER['REQUEST_URI']))
2230
			$this->_requestUri=$_SERVER['REQUEST_URI'];
2231
		else  			$this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
2232
		if(isset($_SERVER['PATH_INFO']))
2233
			$this->_pathInfo=$_SERVER['PATH_INFO'];
2234
		else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
2235
			$this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
2236
		else
2237
			$this->_pathInfo='';
2238
		if(get_magic_quotes_gpc())
2239
		{
2240
			if(isset($_GET))
2241
				$_GET=$this->stripSlashes($_GET);
2242
			if(isset($_POST))
2243
				$_POST=$this->stripSlashes($_POST);
2244
			if(isset($_REQUEST))
2245
				$_REQUEST=$this->stripSlashes($_REQUEST);
2246
			if(isset($_COOKIE))
2247
				$_COOKIE=$this->stripSlashes($_COOKIE);
2248
		}
2249
		$this->getApplication()->setRequest($this);
2250
	}
2251
	public function stripSlashes(&$data)
2252
	{
2253
		return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
2254
	}
2255
	public function getUrl()
2256
	{
2257
		if($this->_url===null)
2258
		{
2259
			$secure=$this->getIsSecureConnection();
2260
			$url=$secure?'https://':'http://';
2261
			if(empty($_SERVER['HTTP_HOST']))
2262
			{
2263
				$url.=$_SERVER['SERVER_NAME'];
2264
				$port=$_SERVER['SERVER_PORT'];
2265
				if(($port!=80 && !$secure) || ($port!=443 && $secure))
2266
					$url.=':'.$port;
2267
			}
2268
			else
2269
				$url.=$_SERVER['HTTP_HOST'];
2270
			$url.=$this->getRequestUri();
2271
			$this->_url=new TUri($url);
2272
		}
2273
		return $this->_url;
2274
	}
2275
	public function getUrlManager()
2276
	{
2277
		return $this->_urlManagerID;
2278
	}
2279
	public function setUrlManager($value)
2280
	{
2281
		$this->_urlManagerID=$value;
2282
	}
2283
	public function getUrlManagerModule()
2284
	{
2285
		return $this->_urlManager;
2286
	}
2287
	public function getUrlFormat()
2288
	{
2289
		return $this->_urlFormat;
2290
	}
2291
	public function setUrlFormat($value)
2292
	{
2293
		$this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
2294
	}
2295
	public function getUrlParamSeparator()
2296
	{
2297
		return $this->_separator;
2298
	}
2299
	public function setUrlParamSeparator($value)
2300
	{
2301
		if(strlen($value)===1)
2302
			$this->_separator=$value;
2303
		else
2304
			throw new TInvalidDataValueException('httprequest_separator_invalid');
2305
	}
2306
	public function getRequestType()
2307
	{
2308
		return $_SERVER['REQUEST_METHOD'];
2309
	}
2310
	public function getIsSecureConnection()
2311
	{
2312
	    return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
2313
	}
2314
	public function getPathInfo()
2315
	{
2316
		return $this->_pathInfo;
2317
	}
2318
	public function getQueryString()
2319
	{
2320
		return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:'';
2321
	}
2322
	public function getHttpProtocolVersion ()
2323
	{
2324
		return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:'';
2325
	}
2326
	public function getRequestUri()
2327
	{
2328
		return $this->_requestUri;
2329
	}
2330
	public function getBaseUrl($forceSecureConnection=false)
2331
	{
2332
		$url=$this->getUrl();
2333
		$scheme=($forceSecureConnection)?"https":$url->getScheme();
2334
		$host=$url->getHost();
2335
		if (($port=$url->getPort())) $host.=':'.$port;
2336
		return $scheme.'://'.$host;
2337
	}
2338
	public function getApplicationUrl()
2339
	{
2340
		return $_SERVER['SCRIPT_NAME'];
2341
	}
2342
	public function getAbsoluteApplicationUrl($forceSecureConnection=false)
2343
	{
2344
		return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
2345
	}
2346
	public function getApplicationFilePath()
2347
	{
2348
		return realpath($_SERVER['SCRIPT_FILENAME']);
2349
	}
2350
	public function getServerName()
2351
	{
2352
		return $_SERVER['SERVER_NAME'];
2353
	}
2354
	public function getServerPort()
2355
	{
2356
		return $_SERVER['SERVER_PORT'];
2357
	}
2358
	public function getUrlReferrer()
2359
	{
2360
		return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
2361
	}
2362
	public function getBrowser()
2363
	{
2364
	    try
2365
	    {
2366
		    return get_browser();
2367
	    }
2368
	    catch(TPhpErrorException $e)
2369
	    {
2370
	        throw new TConfigurationException('httprequest_browscap_required');
2371
	    }
2372
	}
2373
	public function getUserAgent()
2374
	{
2375
		return $_SERVER['HTTP_USER_AGENT'];
2376
	}
2377
	public function getUserHostAddress()
2378
	{
2379
		return $_SERVER['REMOTE_ADDR'];
2380
	}
2381
	public function getUserHost()
2382
	{
2383
		return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
2384
	}
2385
	public function getAcceptTypes()
2386
	{
2387
				return $_SERVER['HTTP_ACCEPT'];
2388
	}
2389
	public function getUserLanguages()
2390
	{
2391
		return Prado::getUserLanguages();
2392
	}
2393
	public function getEnableCookieValidation()
2394
	{
2395
		return $this->_enableCookieValidation;
2396
	}
2397
	public function setEnableCookieValidation($value)
2398
	{
2399
		$this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
2400
	}
2401
	public function getCookies()
2402
	{
2403
		if($this->_cookies===null)
2404
		{
2405
			$this->_cookies=new THttpCookieCollection;
2406
			if($this->getEnableCookieValidation())
2407
			{
2408
				$sm=$this->getApplication()->getSecurityManager();
2409
				foreach($_COOKIE as $key=>$value)
2410
				{
2411
					if(($value=$sm->validateData($value))!==false)
2412
						$this->_cookies->add(new THttpCookie($key,$value));
2413
				}
2414
			}
2415
			else
2416
			{
2417
				foreach($_COOKIE as $key=>$value)
2418
					$this->_cookies->add(new THttpCookie($key,$value));
2419
			}
2420
		}
2421
		return $this->_cookies;
2422
	}
2423
	public function getUploadedFiles()
2424
	{
2425
		return $_FILES;
2426
	}
2427
	public function getServerVariables()
2428
	{
2429
		return $_SERVER;
2430
	}
2431
	public function getEnvironmentVariables()
2432
	{
2433
		return $_ENV;
2434
	}
2435
	public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
2436
	{
2437
		$url=$this->_urlManager->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
2438
		if(defined('SID') && SID != '' && !$this->_cookieOnly)
2439
			return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&amp;':'&')) . SID;
2440
		else
2441
			return $url;
2442
	}
2443
	protected function parseUrl()
2444
	{
2445
		return $this->_urlManager->parseUrl();
2446
	}
2447
	public function resolveRequest($serviceIDs)
2448
	{
2449
		$getParams=$this->parseUrl();
2450
		foreach($getParams as $name=>$value)
2451
			$_GET[$name]=$value;
2452
		$this->_items=array_merge($_GET,$_POST);
2453
		$this->_requestResolved=true;
2454
		foreach($serviceIDs as $serviceID)
2455
		{
2456
			if($this->contains($serviceID))
2457
			{
2458
				$this->setServiceID($serviceID);
2459
				$this->setServiceParameter($this->itemAt($serviceID));
2460
				return $serviceID;
2461
			}
2462
		}
2463
		return null;
2464
	}
2465
	public function getRequestResolved()
2466
	{
2467
		return $this->_requestResolved;
2468
	}
2469
	public function getServiceID()
2470
	{
2471
		return $this->_serviceID;
2472
	}
2473
	public function setServiceID($value)
2474
	{
2475
		$this->_serviceID=$value;
2476
	}
2477
	public function getServiceParameter()
2478
	{
2479
		return $this->_serviceParam;
2480
	}
2481
	public function setServiceParameter($value)
2482
	{
2483
		$this->_serviceParam=$value;
2484
	}
2485
	public function getIterator()
2486
	{
2487
		return new TMapIterator($this->_items);
2488
	}
2489
	public function getCount()
2490
	{
2491
		return count($this->_items);
2492
	}
2493
	public function count()
2494
	{
2495
		return $this->getCount();
2496
	}
2497
	public function getKeys()
2498
	{
2499
		return array_keys($this->_items);
2500
	}
2501
	public function itemAt($key)
2502
	{
2503
		return isset($this->_items[$key]) ? $this->_items[$key] : null;
2504
	}
2505
	public function add($key,$value)
2506
	{
2507
		$this->_items[$key]=$value;
2508
	}
2509
	public function remove($key)
2510
	{
2511
		if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
2512
		{
2513
			$value=$this->_items[$key];
2514
			unset($this->_items[$key]);
2515
			return $value;
2516
		}
2517
		else
2518
			return null;
2519
	}
2520
	public function clear()
2521
	{
2522
		foreach(array_keys($this->_items) as $key)
2523
			$this->remove($key);
2524
	}
2525
	public function contains($key)
2526
	{
2527
		return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
2528
	}
2529
	public function toArray()
2530
	{
2531
		return $this->_items;
2532
	}
2533
	public function offsetExists($offset)
2534
	{
2535
		return $this->contains($offset);
2536
	}
2537
	public function offsetGet($offset)
2538
	{
2539
		return $this->itemAt($offset);
2540
	}
2541
	public function offsetSet($offset,$item)
2542
	{
2543
		$this->add($offset,$item);
2544
	}
2545
	public function offsetUnset($offset)
2546
	{
2547
		$this->remove($offset);
2548
	}
2549
}
2550
class THttpCookieCollection extends TList
2551
{
2552
	private $_o;
2553
	public function __construct($owner=null)
2554
	{
2555
		$this->_o=$owner;
2556
	}
2557
	public function insertAt($index,$item)
2558
	{
2559
		if($item instanceof THttpCookie)
2560
		{
2561
			parent::insertAt($index,$item);
2562
			if($this->_o instanceof THttpResponse)
2563
				$this->_o->addCookie($item);
2564
		}
2565
		else
2566
			throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
2567
	}
2568
	public function removeAt($index)
2569
	{
2570
		$item=parent::removeAt($index);
2571
		if($this->_o instanceof THttpResponse)
2572
			$this->_o->removeCookie($item);
2573
		return $item;
2574
	}
2575
	public function itemAt($index)
2576
	{
2577
		if(is_integer($index))
2578
			return parent::itemAt($index);
2579
		else
2580
			return $this->findCookieByName($index);
2581
	}
2582
	public function findCookieByName($name)
2583
	{
2584
		foreach($this as $cookie)
2585
			if($cookie->getName()===$name)
2586
				return $cookie;
2587
		return null;
2588
	}
2589
}
2590
class THttpCookie extends TComponent
2591
{
2592
	private $_domain='';
2593
	private $_name;
2594
	private $_value='';
2595
	private $_expire=0;
2596
	private $_path='/';
2597
	private $_secure=false;
2598
	public function __construct($name,$value)
2599
	{
2600
		$this->_name=$name;
2601
		$this->_value=$value;
2602
	}
2603
	public function getDomain()
2604
	{
2605
		return $this->_domain;
2606
	}
2607
	public function setDomain($value)
2608
	{
2609
		$this->_domain=$value;
2610
	}
2611
	public function getExpire()
2612
	{
2613
		return $this->_expire;
2614
	}
2615
	public function setExpire($value)
2616
	{
2617
		$this->_expire=TPropertyValue::ensureInteger($value);
2618
	}
2619
	public function getName()
2620
	{
2621
		return $this->_name;
2622
	}
2623
	public function setName($value)
2624
	{
2625
		$this->_name=$value;
2626
	}
2627
	public function getValue()
2628
	{
2629
		return $this->_value;
2630
	}
2631
	public function setValue($value)
2632
	{
2633
		$this->_value=$value;
2634
	}
2635
	public function getPath()
2636
	{
2637
		return $this->_path;
2638
	}
2639
	public function setPath($value)
2640
	{
2641
		$this->_path=$value;
2642
	}
2643
	public function getSecure()
2644
	{
2645
		return $this->_secure;
2646
	}
2647
	public function setSecure($value)
2648
	{
2649
		$this->_secure=TPropertyValue::ensureBoolean($value);
2650
	}
2651
}
2652
class TUri extends TComponent
2653
{
2654
	private static $_defaultPort=array(
2655
		'ftp'=>21,
2656
		'gopher'=>70,
2657
		'http'=>80,
2658
		'https'=>443,
2659
		'news'=>119,
2660
		'nntp'=>119,
2661
		'wais'=>210,
2662
		'telnet'=>23
2663
	);
2664
	private $_scheme;
2665
	private $_host;
2666
	private $_port;
2667
	private $_user;
2668
	private $_pass;
2669
	private $_path;
2670
	private $_query;
2671
	private $_fragment;
2672
	private $_uri;
2673
	public function __construct($uri)
2674
	{
2675
		if(($ret=@parse_url($uri))!==false)
2676
		{
2677
						$this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
2678
			$this->_host=isset($ret['host'])?$ret['host']:'';
2679
			$this->_port=isset($ret['port'])?$ret['port']:'';
2680
			$this->_user=isset($ret['user'])?$ret['user']:'';
2681
			$this->_pass=isset($ret['pass'])?$ret['pass']:'';
2682
			$this->_path=isset($ret['path'])?$ret['path']:'';
2683
			$this->_query=isset($ret['query'])?$ret['query']:'';
2684
			$this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
2685
			$this->_uri=$uri;
2686
		}
2687
		else
2688
		{
2689
			throw new TInvalidDataValueException('uri_format_invalid',$uri);
2690
		}
2691
	}
2692
	public function getUri()
2693
	{
2694
		return $this->_uri;
2695
	}
2696
	public function getScheme()
2697
	{
2698
		return $this->_scheme;
2699
	}
2700
	public function getHost()
2701
	{
2702
		return $this->_host;
2703
	}
2704
	public function getPort()
2705
	{
2706
		return $this->_port;
2707
	}
2708
	public function getUser()
2709
	{
2710
		return $this->_user;
2711
	}
2712
	public function getPassword()
2713
	{
2714
		return $this->_pass;
2715
	}
2716
	public function getPath()
2717
	{
2718
		return $this->_path;
2719
	}
2720
	public function getQuery()
2721
	{
2722
		return $this->_query;
2723
	}
2724
	public function getFragment()
2725
	{
2726
		return $this->_fragment;
2727
	}
2728
}
2729
class THttpRequestUrlFormat extends TEnumerable
2730
{
2731
	const Get='Get';
2732
	const Path='Path';
2733
}
2734
class THttpResponseAdapter extends TApplicationComponent
2735
{
2736
	private $_response;
2737
	public function __construct($response)
2738
	{
2739
		$this->_response=$response;
2740
	}
2741
	public function getResponse()
2742
	{
2743
		return $this->_response;
2744
	}
2745
	public function flushContent()
2746
	{
2747
		$this->_response->flushContent();
2748
	}
2749
	public function httpRedirect($url)
2750
	{
2751
		$this->_response->httpRedirect($url);
2752
	}
2753
	public function createNewHtmlWriter($type, $writer)
2754
	{
2755
		return $this->_response->createNewHtmlWriter($type,$writer);
2756
	}
2757
}
2758
class THttpResponse extends TModule implements ITextWriter
2759
{
2760
	private static $HTTP_STATUS_CODES = array(
2761
		100 => 'Continue', 101 => 'Switching Protocols',
2762
		200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
2763
		300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
2764
		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',
2765
		500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
2766
	);
2767
	private $_bufferOutput=true;
2768
	private $_initialized=false;
2769
	private $_cookies=null;
2770
	private $_status=200;
2771
	private $_reason='OK';
2772
	private $_htmlWriterType='System.Web.UI.THtmlWriter';
2773
	private $_contentType=null;
2774
	private $_charset='';
2775
	private $_adapter;
2776
	public function __destruct()
2777
	{
2778
					}
2779
	public function setAdapter(THttpResponseAdapter $adapter)
2780
	{
2781
		$this->_adapter=$adapter;
2782
	}
2783
	public function getAdapter()
2784
	{
2785
		return $this->_adapter;
2786
	}
2787
	public function getHasAdapter()
2788
	{
2789
		return !is_null($this->_adapter);
2790
	}
2791
	public function init($config)
2792
	{
2793
		if($this->_bufferOutput)
2794
			ob_start();
2795
		$this->_initialized=true;
2796
		$this->getApplication()->setResponse($this);
2797
	}
2798
	public function getCacheExpire()
2799
	{
2800
		return session_cache_expire();
2801
	}
2802
	public function setCacheExpire($value)
2803
	{
2804
		session_cache_expire(TPropertyValue::ensureInteger($value));
2805
	}
2806
	public function getCacheControl()
2807
	{
2808
		return session_cache_limiter();
2809
	}
2810
	public function setCacheControl($value)
2811
	{
2812
		session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
2813
	}
2814
	public function setContentType($type)
2815
	{
2816
		$this->_contentType = $type;
2817
	}
2818
	public function getContentType()
2819
	{
2820
		return $this->_contentType;
2821
	}
2822
	public function getCharset()
2823
	{
2824
		return $this->_charset;
2825
	}
2826
	public function setCharset($charset)
2827
	{
2828
		$this->_charset = $charset;
2829
	}
2830
	public function getBufferOutput()
2831
	{
2832
		return $this->_bufferOutput;
2833
	}
2834
	public function setBufferOutput($value)
2835
	{
2836
		if($this->_initialized)
2837
			throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
2838
		else
2839
			$this->_bufferOutput=TPropertyValue::ensureBoolean($value);
2840
	}
2841
	public function getStatusCode()
2842
	{
2843
		return $this->_status;
2844
	}
2845
	public function setStatusCode($status, $reason=null)
2846
	{
2847
		$status=TPropertyValue::ensureInteger($status);
2848
		if(isset(self::$HTTP_STATUS_CODES[$status])) {
2849
			$this->_reason=self::$HTTP_STATUS_CODES[$status];
2850
		}else{
2851
			if($reason===null || $reason==='') {
2852
				throw new TInvalidDataValueException("response_status_reason_missing");
2853
			}
2854
			$reason=TPropertyValue::ensureString($reason);
2855
			if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
2856
				throw new TInvalidDataValueException("response_status_reason_barchars");
2857
			}
2858
			$this->_reason=$reason;
2859
		}
2860
		$this->_status=$status;
2861
	}
2862
	public function getStatusReason() {
2863
		return $this->_reason;
2864
	}
2865
	public function getCookies()
2866
	{
2867
		if($this->_cookies===null)
2868
			$this->_cookies=new THttpCookieCollection($this);
2869
		return $this->_cookies;
2870
	}
2871
	public function write($str)
2872
	{
2873
		echo $str;
2874
	}
2875
	public function writeFile($fileName,$content=null,$mimeType=null,$headers=null)
2876
	{
2877
		static $defaultMimeTypes=array(
2878
			'css'=>'text/css',
2879
			'gif'=>'image/gif',
2880
			'jpg'=>'image/jpeg',
2881
			'jpeg'=>'image/jpeg',
2882
			'htm'=>'text/html',
2883
			'html'=>'text/html',
2884
			'js'=>'javascript/js',
2885
			'pdf'=>'application/pdf',
2886
			'xls'=>'application/vnd.ms-excel',
2887
		);
2888
		if($mimeType===null)
2889
		{
2890
			$mimeType='text/plain';
2891
			if(function_exists('mime_content_type'))
2892
				$mimeType=mime_content_type($fileName);
2893
			else if(($ext=strrchr($fileName,'.'))!==false)
2894
			{
2895
				$ext=substr($ext,1);
2896
				if(isset($defaultMimeTypes[$ext]))
2897
					$mimeType=$defaultMimeTypes[$ext];
2898
			}
2899
		}
2900
		$fn=basename($fileName);
2901
		$this->sendHttpHeader();
2902
		if(is_array($headers))
2903
		{
2904
			foreach($headers as $h)
2905
				header($h);
2906
		}
2907
		else
2908
		{
2909
			header('Pragma: public');
2910
			header('Expires: 0');
2911
			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
2912
		}
2913
		header("Content-type: $mimeType");
2914
		header('Content-Length: '.($content===null?filesize($fileName):strlen($content)));
2915
		header("Content-Disposition: attachment; filename=\"$fn\"");
2916
		header('Content-Transfer-Encoding: binary');
2917
		if($content===null)
2918
			readfile($fileName);
2919
		else
2920
			echo $content;
2921
	}
2922
	public function redirect($url)
2923
	{
2924
		if($this->getHasAdapter())
2925
			$this->_adapter->httpRedirect($url);
2926
		else
2927
			$this->httpRedirect($url);
2928
	}
2929
	public function httpRedirect($url)
2930
	{
2931
		if(!$this->getApplication()->getRequestCompleted())
2932
			$this->getApplication()->onEndRequest();
2933
		if($url[0]==='/')
2934
			$url=$this->getRequest()->getBaseUrl().$url;
2935
		header('Location: '.str_replace('&amp;','&',$url));
2936
		exit();
2937
	}
2938
	public function reload()
2939
	{
2940
		$this->redirect($this->getRequest()->getRequestUri());
2941
	}
2942
	public function flush()
2943
	{
2944
		if($this->getHasAdapter())
2945
			$this->_adapter->flushContent();
2946
		else
2947
			$this->flushContent();
2948
	}
2949
	public function flushContent()
2950
	{
2951
		$this->sendHttpHeader();
2952
		$this->sendContentTypeHeader();
2953
		if($this->_bufferOutput)
2954
			ob_flush();
2955
	}
2956
	protected function sendHttpHeader ()
2957
	{
2958
		if (($version=$this->getRequest()->getHttpProtocolVersion())==='')
2959
			header (' ', true, $this->_status);
2960
		else
2961
			header($version.' '.$this->_status.' '.$this->_reason, true, $this->_status);
2962
	}
2963
	protected function sendContentTypeHeader()
2964
	{
2965
		$charset=$this->getCharset();
2966
		if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
2967
			$charset=$globalization->getCharset();
2968
		if($charset!=='')
2969
		{
2970
			$contentType=$this->_contentType===null?'text/html':$this->_contentType;
2971
			$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
2972
		}
2973
		else if($this->_contentType!==null)
2974
			$this->appendHeader('Content-Type: '.$this->_contentType.';charset=UTF-8');
2975
	}
2976
	public function getContents()
2977
	{
2978
		return $this->_bufferOutput?ob_get_contents():'';
2979
	}
2980
	public function clear()
2981
	{
2982
		if($this->_bufferOutput)
2983
			ob_clean();
2984
	}
2985
	public function appendHeader($value)
2986
	{
2987
		header($value);
2988
	}
2989
	public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
2990
	{
2991
		error_log($message,$messageType,$destination,$extraHeaders);
2992
	}
2993
	public function addCookie($cookie)
2994
	{
2995
		$request=$this->getRequest();
2996
		if($request->getEnableCookieValidation())
2997
		{
2998
			$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
2999
			setcookie($cookie->getName(),$value,$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());
3000
		}
3001
		else
3002
			setcookie($cookie->getName(),$cookie->getValue(),$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());
3003
	}
3004
	public function removeCookie($cookie)
3005
	{
3006
		setcookie($cookie->getName(),null,0,$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());
3007
	}
3008
	public function getHtmlWriterType()
3009
	{
3010
		return $this->_htmlWriterType;
3011
	}
3012
	public function setHtmlWriterType($value)
3013
	{
3014
		$this->_htmlWriterType=$value;
3015
	}
3016
	public function createHtmlWriter($type=null)
3017
	{
3018
		if($type===null)
3019
			$type=$this->getHtmlWriterType();
3020
		if($this->getHasAdapter())
3021
			return $this->_adapter->createNewHtmlWriter($type, $this);
3022
		else
3023
		 	return $this->createNewHtmlWriter($type, $this);
3024
	}
3025
	public function createNewHtmlWriter($type, $writer)
3026
	{
3027
		return Prado::createComponent($type, $writer);
3028
	}
3029
}
3030
class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
3031
{
3032
	private $_initialized=false;
3033
	private $_started=false;
3034
	private $_autoStart=false;
3035
	private $_cookie=null;
3036
	private $_id;
3037
	private $_customStorage=false;
3038
	public function getID()
3039
	{
3040
		return $this->_id;
3041
	}
3042
	public function setID($value)
3043
	{
3044
		$this->_id=$value;
3045
	}
3046
	public function init($config)
3047
	{
3048
		if($this->_autoStart)
3049
			$this->open();
3050
		$this->_initialized=true;
3051
		$this->getApplication()->setSession($this);
3052
		register_shutdown_function(array($this, "close"));
3053
	}
3054
	public function open()
3055
	{
3056
		if(!$this->_started)
3057
		{
3058
			if($this->_customStorage)
3059
				session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
3060
			if($this->_cookie!==null)
3061
				session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure());
3062
			if(ini_get('session.auto_start')!=='1')
3063
				session_start();
3064
			$this->_started=true;
3065
		}
3066
	}
3067
	public function close()
3068
	{
3069
		if($this->_started)
3070
		{
3071
			session_write_close();
3072
			$this->_started=false;
3073
		}
3074
	}
3075
	public function destroy()
3076
	{
3077
		if($this->_started)
3078
		{
3079
			session_destroy();
3080
			$this->_started=false;
3081
		}
3082
	}
3083
	public function getIsStarted()
3084
	{
3085
		return $this->_started;
3086
	}
3087
	public function getSessionID()
3088
	{
3089
		return session_id();
3090
	}
3091
	public function setSessionID($value)
3092
	{
3093
		if($this->_started)
3094
			throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
3095
		else
3096
			session_id($value);
3097
	}
3098
	public function getSessionName()
3099
	{
3100
		return session_name();
3101
	}
3102
	public function setSessionName($value)
3103
	{
3104
		if($this->_started)
3105
			throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
3106
		else if(ctype_alnum($value))
3107
			session_name($value);
3108
		else
3109
			throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
3110
	}
3111
	public function getSavePath()
3112
	{
3113
		return session_save_path();
3114
	}
3115
	public function setSavePath($value)
3116
	{
3117
		if($this->_started)
3118
			throw new TInvalidOperationException('httpsession_savepath_unchangeable');
3119
		else if(is_dir($value))
3120
			session_save_path($value);
3121
		else
3122
			throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
3123
	}
3124
	public function getUseCustomStorage()
3125
	{
3126
		return $this->_customStorage;
3127
	}
3128
	public function setUseCustomStorage($value)
3129
	{
3130
		$this->_customStorage=TPropertyValue::ensureBoolean($value);
3131
	}
3132
	public function getCookie()
3133
	{
3134
		if($this->_cookie===null)
3135
			$this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
3136
		return $this->_cookie;
3137
	}
3138
	public function getCookieMode()
3139
	{
3140
		if(ini_get('session.use_cookies')==='0')
3141
			return THttpSessionCookieMode::None;
3142
		else if(ini_get('session.use_only_cookies')==='0')
3143
			return THttpSessionCookieMode::Allow;
3144
		else
3145
			return THttpSessionCookieMode::Only;
3146
	}
3147
	public function setCookieMode($value)
3148
	{
3149
		if($this->_started)
3150
			throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
3151
		else
3152
		{
3153
			$value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
3154
			if($value===THttpSessionCookieMode::None)
3155
				ini_set('session.use_cookies','0');
3156
			else if($value===THttpSessionCookieMode::Allow)
3157
			{
3158
				ini_set('session.use_cookies','1');
3159
				ini_set('session.use_only_cookies','0');
3160
			}
3161
			else
3162
			{
3163
				ini_set('session.use_cookies','1');
3164
				ini_set('session.use_only_cookies','1');
3165
			}
3166
		}
3167
	}
3168
	public function getAutoStart()
3169
	{
3170
		return $this->_autoStart;
3171
	}
3172
	public function setAutoStart($value)
3173
	{
3174
		if($this->_initialized)
3175
			throw new TInvalidOperationException('httpsession_autostart_unchangeable');
3176
		else
3177
			$this->_autoStart=TPropertyValue::ensureBoolean($value);
3178
	}
3179
	public function getGCProbability()
3180
	{
3181
		return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
3182
	}
3183
	public function setGCProbability($value)
3184
	{
3185
		if($this->_started)
3186
			throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
3187
		else
3188
		{
3189
			$value=TPropertyValue::ensureInteger($value);
3190
			if($value>=0 && $value<=100)
3191
			{
3192
				ini_set('session.gc_probability',$value);
3193
				ini_set('session.gc_divisor','100');
3194
			}
3195
			else
3196
				throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
3197
		}
3198
	}
3199
	public function getUseTransparentSessionID()
3200
	{
3201
		return ini_get('session.use_trans_sid')==='1';
3202
	}
3203
	public function setUseTransparentSessionID($value)
3204
	{
3205
		if($this->_started)
3206
			throw new TInvalidOperationException('httpsession_transid_unchangeable');
3207
		else
3208
			ini_set('session.use_trans_sid',TPropertyValue::ensureBoolean($value)?'1':'0');
3209
	}
3210
	public function getTimeout()
3211
	{
3212
		return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
3213
	}
3214
	public function setTimeout($value)
3215
	{
3216
		if($this->_started)
3217
			throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
3218
		else
3219
			ini_set('session.gc_maxlifetime',$value);
3220
	}
3221
	public function _open($savePath,$sessionName)
3222
	{
3223
		return true;
3224
	}
3225
	public function _close()
3226
	{
3227
		return true;
3228
	}
3229
	public function _read($id)
3230
	{
3231
		return '';
3232
	}
3233
	public function _write($id,$data)
3234
	{
3235
		return true;
3236
	}
3237
	public function _destroy($id)
3238
	{
3239
		return true;
3240
	}
3241
	public function _gc($maxLifetime)
3242
	{
3243
		return true;
3244
	}
3245
	public function getIterator()
3246
	{
3247
		return new TSessionIterator;
3248
	}
3249
	public function getCount()
3250
	{
3251
		return count($_SESSION);
3252
	}
3253
	public function count()
3254
	{
3255
		return $this->getCount();
3256
	}
3257
	public function getKeys()
3258
	{
3259
		return array_keys($_SESSION);
3260
	}
3261
	public function itemAt($key)
3262
	{
3263
		return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
3264
	}
3265
	public function add($key,$value)
3266
	{
3267
		$_SESSION[$key]=$value;
3268
	}
3269
	public function remove($key)
3270
	{
3271
		if(isset($_SESSION[$key]))
3272
		{
3273
			$value=$_SESSION[$key];
3274
			unset($_SESSION[$key]);
3275
			return $value;
3276
		}
3277
		else
3278
			return null;
3279
	}
3280
	public function clear()
3281
	{
3282
		foreach(array_keys($_SESSION) as $key)
3283
			unset($_SESSION[$key]);
3284
	}
3285
	public function contains($key)
3286
	{
3287
		return isset($_SESSION[$key]);
3288
	}
3289
	public function toArray()
3290
	{
3291
		return $_SESSION;
3292
	}
3293
	public function offsetExists($offset)
3294
	{
3295
		return isset($_SESSION[$offset]);
3296
	}
3297
	public function offsetGet($offset)
3298
	{
3299
		return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
3300
	}
3301
	public function offsetSet($offset,$item)
3302
	{
3303
		$_SESSION[$offset]=$item;
3304
	}
3305
	public function offsetUnset($offset)
3306
	{
3307
		unset($_SESSION[$offset]);
3308
	}
3309
}
3310
class TSessionIterator implements Iterator
3311
{
3312
	private $_keys;
3313
	private $_key;
3314
	public function __construct()
3315
	{
3316
		$this->_keys=array_keys($_SESSION);
3317
	}
3318
	public function rewind()
3319
	{
3320
		$this->_key=reset($this->_keys);
3321
	}
3322
	public function key()
3323
	{
3324
		return $this->_key;
3325
	}
3326
	public function current()
3327
	{
3328
		return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
3329
	}
3330
	public function next()
3331
	{
3332
		do
3333
		{
3334
			$this->_key=next($this->_keys);
3335
		}
3336
		while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
3337
	}
3338
	public function valid()
3339
	{
3340
		return $this->_key!==false;
3341
	}
3342
}
3343
class THttpSessionCookieMode extends TEnumerable
3344
{
3345
	const None='None';
3346
	const Allow='Allow';
3347
	const Only='Only';
3348
}
3349
Prado::using('System.Web.UI.WebControls.*');
3350
class TAttributeCollection extends TMap
3351
{
3352
	private $_caseSensitive=false;
3353
	public function __get($name)
3354
	{
3355
		return $this->contains($name)?$this->itemAt($name):parent::__get($name);
3356
	}
3357
	public function __set($name,$value)
3358
	{
3359
		$this->add($name,$value);
3360
	}
3361
	public function getCaseSensitive()
3362
	{
3363
		return $this->_caseSensitive;
3364
	}
3365
	public function setCaseSensitive($value)
3366
	{
3367
		$this->_caseSensitive=TPropertyValue::ensureBoolean($value);
3368
	}
3369
	public function itemAt($key)
3370
	{
3371
		return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
3372
	}
3373
	public function add($key,$value)
3374
	{
3375
		parent::add($this->_caseSensitive?$key:strtolower($key),$value);
3376
	}
3377
	public function remove($key)
3378
	{
3379
		return parent::remove($this->_caseSensitive?$key:strtolower($key));
3380
	}
3381
	public function contains($key)
3382
	{
3383
		return parent::contains($this->_caseSensitive?$key:strtolower($key));
3384
	}
3385
	public function hasProperty($name)
3386
	{
3387
		return $this->contains($name) || parent::hasProperty($name);
3388
	}
3389
	public function canGetProperty($name)
3390
	{
3391
		return $this->contains($name) || parent::canGetProperty($name);
3392
	}
3393
	public function canSetProperty($name)
3394
	{
3395
		return true;
3396
	}
3397
}
3398
class TControlAdapter extends TApplicationComponent
3399
{
3400
	private $_control;
3401
	public function __construct($control)
3402
	{
3403
		$this->_control=$control;
3404
	}
3405
	public function getControl()
3406
	{
3407
		return $this->_control;
3408
	}
3409
	public function getPage()
3410
	{
3411
		return $this->_control?$this->_control->getPage():null;
3412
	}
3413
	public function createChildControls()
3414
	{
3415
		$this->_control->createChildControls();
3416
	}
3417
	public function loadState()
3418
	{
3419
		$this->_control->loadState();
3420
	}
3421
	public function saveState()
3422
	{
3423
		$this->_control->saveState();
3424
	}
3425
	public function onInit($param)
3426
	{
3427
		$this->_control->onInit($param);
3428
	}
3429
	public function onLoad($param)
3430
	{
3431
		$this->_control->onLoad($param);
3432
	}
3433
	public function onPreRender($param)
3434
	{
3435
		$this->_control->onPreRender($param);
3436
	}
3437
	public function onUnload($param)
3438
	{
3439
		$this->_control->onUnload($param);
3440
	}
3441
	public function render($writer)
3442
	{
3443
		$this->_control->render($writer);
3444
	}
3445
	public function renderChildren($writer)
3446
	{
3447
		$this->_control->renderChildren($writer);
3448
	}
3449
}
3450
class TControl extends TApplicationComponent implements IRenderable, IBindable
3451
{
3452
	const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
3453
	const ID_SEPARATOR='$';
3454
	const CLIENT_ID_SEPARATOR='_';
3455
	const AUTOMATIC_ID_PREFIX='ctl';
3456
	const CS_CONSTRUCTED=0;
3457
	const CS_CHILD_INITIALIZED=1;
3458
	const CS_INITIALIZED=2;
3459
	const CS_STATE_LOADED=3;
3460
	const CS_LOADED=4;
3461
	const CS_PRERENDERED=5;
3462
	const IS_ID_SET=0x01;
3463
	const IS_DISABLE_VIEWSTATE=0x02;
3464
	const IS_SKIN_APPLIED=0x04;
3465
	const IS_STYLESHEET_APPLIED=0x08;
3466
	const IS_DISABLE_THEMING=0x10;
3467
	const IS_CHILD_CREATED=0x20;
3468
	const IS_CREATING_CHILD=0x40;
3469
	const RF_CONTROLS=0;
3470
	const RF_CHILD_STATE=1;
3471
	const RF_NAMED_CONTROLS=2;
3472
	const RF_NAMED_CONTROLS_ID=3;
3473
	const RF_SKIN_ID=4;
3474
	const RF_DATA_BINDINGS=5;
3475
	const RF_EVENTS=6;
3476
	const RF_CONTROLSTATE=7;
3477
	const RF_NAMED_OBJECTS=8;
3478
	const RF_ADAPTER=9;
3479
	const RF_AUTO_BINDINGS=10;
3480
	private $_id='';
3481
	private $_uid;
3482
	private $_parent;
3483
	private $_page;
3484
	private $_namingContainer;
3485
	private $_tplControl;
3486
	private $_viewState=array();
3487
	private $_tempState=array();
3488
	private $_trackViewState=true;
3489
	private $_stage=0;
3490
	private $_flags=0;
3491
	private $_rf=array();
3492
	public function __construct()
3493
	{
3494
	}
3495
	public function __get($name)
3496
	{
3497
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
3498
			return $this->_rf[self::RF_NAMED_OBJECTS][$name];
3499
		else
3500
			return parent::__get($name);
3501
	}
3502
	public function getHasAdapter()
3503
	{
3504
		return isset($this->_rf[self::RF_ADAPTER]);
3505
	}
3506
	public function getAdapter()
3507
	{
3508
		return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
3509
	}
3510
	public function setAdapter(TControlAdapter $adapter)
3511
	{
3512
		$this->_rf[self::RF_ADAPTER]=$adapter;
3513
	}
3514
	public function getParent()
3515
	{
3516
		return $this->_parent;
3517
	}
3518
	public function getNamingContainer()
3519
	{
3520
		if(!$this->_namingContainer && $this->_parent)
3521
		{
3522
			if($this->_parent instanceof INamingContainer)
3523
				$this->_namingContainer=$this->_parent;
3524
			else
3525
				$this->_namingContainer=$this->_parent->getNamingContainer();
3526
		}
3527
		return $this->_namingContainer;
3528
	}
3529
	public function getPage()
3530
	{
3531
		if(!$this->_page)
3532
		{
3533
			if($this->_parent)
3534
				$this->_page=$this->_parent->getPage();
3535
			else if($this->_tplControl)
3536
				$this->_page=$this->_tplControl->getPage();
3537
		}
3538
		return $this->_page;
3539
	}
3540
	public function setPage($page)
3541
	{
3542
		$this->_page=$page;
3543
	}
3544
	public function setTemplateControl($control)
3545
	{
3546
		$this->_tplControl=$control;
3547
	}
3548
	public function getTemplateControl()
3549
	{
3550
		if(!$this->_tplControl && $this->_parent)
3551
			$this->_tplControl=$this->_parent->getTemplateControl();
3552
		return $this->_tplControl;
3553
	}
3554
	public function getSourceTemplateControl()
3555
	{
3556
		$control=$this;
3557
		while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
3558
		{
3559
			if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
3560
				return $control;
3561
		}
3562
		return $this->getPage();
3563
	}
3564
	protected function getControlStage()
3565
	{
3566
		return $this->_stage;
3567
	}
3568
	protected function setControlStage($value)
3569
	{
3570
		$this->_stage=$value;
3571
	}
3572
	public function getID($hideAutoID=true)
3573
	{
3574
		if($hideAutoID)
3575
			return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
3576
		else
3577
			return $this->_id;
3578
	}
3579
	public function setID($id)
3580
	{
3581
		if(!preg_match(self::ID_FORMAT,$id))
3582
			throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
3583
		$this->_id=$id;
3584
		$this->_flags |= self::IS_ID_SET;
3585
		$this->clearCachedUniqueID($this instanceof INamingContainer);
3586
		if($this->_namingContainer)
3587
			$this->_namingContainer->clearNameTable();
3588
	}
3589
	public function getUniqueID()
3590
	{
3591
		if($this->_uid==='' || $this->_uid===null)
3592
		{
3593
			$this->_uid='';
3594
			if($namingContainer=$this->getNamingContainer())
3595
			{
3596
				if($this->getPage()===$namingContainer)
3597
					return ($this->_uid=$this->_id);
3598
				else if(($prefix=$namingContainer->getUniqueID())==='')
3599
					return $this->_id;
3600
				else
3601
					return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
3602
			}
3603
			else
3604
				return $this->_id;
3605
		}
3606
		else
3607
			return $this->_uid;
3608
	}
3609
	public function focus()
3610
	{
3611
		$this->getPage()->setFocus($this);
3612
	}
3613
	public function getClientID()
3614
	{
3615
		return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
3616
	}
3617
	public static function convertUniqueIdToClientId($uniqueID)
3618
	{
3619
		return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
3620
	}
3621
	public function getSkinID()
3622
	{
3623
		return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
3624
	}
3625
	public function setSkinID($value)
3626
	{
3627
		if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
3628
			throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
3629
		else
3630
			$this->_rf[self::RF_SKIN_ID]=$value;
3631
	}
3632
	public function getEnableTheming()
3633
	{
3634
		if($this->_flags & self::IS_DISABLE_THEMING)
3635
			return false;
3636
		else
3637
			return $this->_parent?$this->_parent->getEnableTheming():true;
3638
	}
3639
	public function setEnableTheming($value)
3640
	{
3641
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
3642
			throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
3643
		else if(TPropertyValue::ensureBoolean($value))
3644
			$this->_flags &= ~self::IS_DISABLE_THEMING;
3645
		else
3646
			$this->_flags |= self::IS_DISABLE_THEMING;
3647
	}
3648
	public function getCustomData()
3649
	{
3650
		return $this->getViewState('CustomData',null);
3651
	}
3652
	public function setCustomData($value)
3653
	{
3654
		$this->setViewState('CustomData',$value,null);
3655
	}
3656
	public function getHasControls()
3657
	{
3658
		return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
3659
	}
3660
	public function getControls()
3661
	{
3662
		if(!isset($this->_rf[self::RF_CONTROLS]))
3663
			$this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
3664
		return $this->_rf[self::RF_CONTROLS];
3665
	}
3666
	protected function createControlCollection()
3667
	{
3668
		return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
3669
	}
3670
	public function getVisible($checkParents=true)
3671
	{
3672
		if($checkParents)
3673
		{
3674
			for($control=$this;$control;$control=$control->_parent)
3675
				if(!$control->getVisible(false))
3676
					return false;
3677
			return true;
3678
		}
3679
		else
3680
			return $this->getViewState('Visible',true);
3681
	}
3682
	public function setVisible($value)
3683
	{
3684
		$this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
3685
	}
3686
	public function getEnabled($checkParents=false)
3687
	{
3688
		if($checkParents)
3689
		{
3690
			for($control=$this;$control;$control=$control->_parent)
3691
				if(!$control->getViewState('Enabled',true))
3692
					return false;
3693
			return true;
3694
		}
3695
		else
3696
			return $this->getViewState('Enabled',true);
3697
	}
3698
	public function setEnabled($value)
3699
	{
3700
		$this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
3701
	}
3702
	public function getHasAttributes()
3703
	{
3704
		if($attributes=$this->getViewState('Attributes',null))
3705
			return $attributes->getCount()>0;
3706
		else
3707
			return false;
3708
	}
3709
	public function getAttributes()
3710
	{
3711
		if($attributes=$this->getViewState('Attributes',null))
3712
			return $attributes;
3713
		else
3714
		{
3715
			$attributes=new TAttributeCollection;
3716
			$this->setViewState('Attributes',$attributes,null);
3717
			return $attributes;
3718
		}
3719
	}
3720
	public function hasAttribute($name)
3721
	{
3722
		if($attributes=$this->getViewState('Attributes',null))
3723
			return $attributes->contains($name);
3724
		else
3725
			return false;
3726
	}
3727
	public function getAttribute($name)
3728
	{
3729
		if($attributes=$this->getViewState('Attributes',null))
3730
			return $attributes->itemAt($name);
3731
		else
3732
			return null;
3733
	}
3734
	public function setAttribute($name,$value)
3735
	{
3736
		$this->getAttributes()->add($name,$value);
3737
	}
3738
	public function removeAttribute($name)
3739
	{
3740
		if($attributes=$this->getViewState('Attributes',null))
3741
			return $attributes->remove($name);
3742
		else
3743
			return null;
3744
	}
3745
	public function getEnableViewState($checkParents=false)
3746
	{
3747
		if($checkParents)
3748
		{
3749
			for($control=$this;$control!==null;$control=$control->getParent())
3750
				if($control->_flags & self::IS_DISABLE_VIEWSTATE)
3751
					return false;
3752
			return true;
3753
		}
3754
		else
3755
			return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
3756
	}
3757
	public function setEnableViewState($value)
3758
	{
3759
		if(TPropertyValue::ensureBoolean($value))
3760
			$this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
3761
		else
3762
			$this->_flags |= self::IS_DISABLE_VIEWSTATE;
3763
	}
3764
	protected function getControlState($key,$defaultValue=null)
3765
	{
3766
		return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
3767
	}
3768
	protected function setControlState($key,$value,$defaultValue=null)
3769
	{
3770
		if($value===$defaultValue)
3771
			unset($this->_rf[self::RF_CONTROLSTATE][$key]);
3772
		else
3773
			$this->_rf[self::RF_CONTROLSTATE][$key]=$value;
3774
	}
3775
	protected function clearControlState($key)
3776
	{
3777
		unset($this->_rf[self::RF_CONTROLSTATE][$key]);
3778
	}
3779
	public function trackViewState($enabled)
3780
	{
3781
		$this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
3782
	}
3783
	public function getViewState($key,$defaultValue=null)
3784
	{
3785
		if(isset($this->_viewState[$key]))
3786
			return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
3787
		else if(isset($this->_tempState[$key]))
3788
		{
3789
			if(is_object($this->_tempState[$key]) && $this->_trackViewState)
3790
				$this->_viewState[$key]=$this->_tempState[$key];
3791
			return $this->_tempState[$key];
3792
		}
3793
		else
3794
			return $defaultValue;
3795
	}
3796
	public function setViewState($key,$value,$defaultValue=null)
3797
	{
3798
		if($this->_trackViewState)
3799
		{
3800
			$this->_viewState[$key]=$value;
3801
			unset($this->_tempState[$key]);
3802
		}
3803
		else
3804
		{
3805
			unset($this->_viewState[$key]);
3806
			$this->_tempState[$key]=$value;
3807
		}
3808
	}
3809
	public function clearViewState($key)
3810
	{
3811
		unset($this->_viewState[$key]);
3812
		unset($this->_tempState[$key]);
3813
	}
3814
	public function bindProperty($name,$expression)
3815
	{
3816
		$this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
3817
	}
3818
	public function unbindProperty($name)
3819
	{
3820
		unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
3821
	}
3822
	public function autoBindProperty($name,$expression)
3823
	{
3824
		$this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
3825
	}
3826
	public function dataBind()
3827
	{
3828
		$this->dataBindProperties();
3829
		$this->onDataBinding(null);
3830
		$this->dataBindChildren();
3831
	}
3832
	protected function dataBindProperties()
3833
	{
3834
		if(isset($this->_rf[self::RF_DATA_BINDINGS]))
3835
		{
3836
			if(($context=$this->getTemplateControl())===null)
3837
				$context=$this;
3838
			foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
3839
				$this->setSubProperty($property,$context->evaluateExpression($expression));
3840
		}
3841
	}
3842
	protected function autoDataBindProperties()
3843
	{
3844
		if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
3845
		{
3846
			if(($context=$this->getTemplateControl())===null)
3847
				$context=$this;
3848
			foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
3849
				$this->setSubProperty($property,$context->evaluateExpression($expression));
3850
		}
3851
	}
3852
	protected function dataBindChildren()
3853
	{
3854
		if(isset($this->_rf[self::RF_CONTROLS]))
3855
		{
3856
			foreach($this->_rf[self::RF_CONTROLS] as $control)
3857
				if($control instanceof IBindable)
3858
					$control->dataBind();
3859
		}
3860
	}
3861
	final protected function getChildControlsCreated()
3862
	{
3863
		return ($this->_flags & self::IS_CHILD_CREATED)!==0;
3864
	}
3865
	final protected function setChildControlsCreated($value)
3866
	{
3867
		if($value)
3868
			$this->_flags |= self::IS_CHILD_CREATED;
3869
		else
3870
		{
3871
			if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
3872
				$this->getControls()->clear();
3873
			$this->_flags &= ~self::IS_CHILD_CREATED;
3874
		}
3875
	}
3876
	public function ensureChildControls()
3877
	{
3878
		if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
3879
		{
3880
			try
3881
			{
3882
				$this->_flags |= self::IS_CREATING_CHILD;
3883
				if(isset($this->_rf[self::RF_ADAPTER]))
3884
					$this->_rf[self::RF_ADAPTER]->createChildControls();
3885
				else
3886
					$this->createChildControls();
3887
				$this->_flags &= ~self::IS_CREATING_CHILD;
3888
				$this->_flags |= self::IS_CHILD_CREATED;
3889
			}
3890
			catch(Exception $e)
3891
			{
3892
				$this->_flags &= ~self::IS_CREATING_CHILD;
3893
				$this->_flags |= self::IS_CHILD_CREATED;
3894
				throw $e;
3895
			}
3896
		}
3897
	}
3898
	public function createChildControls()
3899
	{
3900
	}
3901
	public function findControl($id)
3902
	{
3903
		$id=strtr($id,'.',self::ID_SEPARATOR);
3904
		$container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
3905
		if(!$container || !$container->getHasControls())
3906
			return null;
3907
		if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
3908
		{
3909
			$container->_rf[self::RF_NAMED_CONTROLS]=array();
3910
			$container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
3911
		}
3912
		if(($pos=strpos($id,self::ID_SEPARATOR))===false)
3913
			return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
3914
		else
3915
		{
3916
			$cid=substr($id,0,$pos);
3917
			$sid=substr($id,$pos+1);
3918
			if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
3919
				return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
3920
			else
3921
				return null;
3922
		}
3923
	}
3924
	public function findControlsByType($type,$strict=true)
3925
	{
3926
		$controls=array();
3927
		if($this->getHasControls())
3928
		{
3929
			foreach($this->_rf[self::RF_CONTROLS] as $control)
3930
			{
3931
				if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
3932
					$controls[]=$control;
3933
				if(($control instanceof TControl) && $control->getHasControls())
3934
					$controls=array_merge($controls,$control->findControlsByType($type,$strict));
3935
			}
3936
		}
3937
		return $controls;
3938
	}
3939
	public function findControlsByID($id)
3940
	{
3941
		$controls=array();
3942
		if($this->getHasControls())
3943
		{
3944
			foreach($this->_rf[self::RF_CONTROLS] as $control)
3945
			{
3946
				if($control instanceof TControl)
3947
				{
3948
					if($control->_id===$id)
3949
						$controls[]=$control;
3950
					$controls=array_merge($controls,$control->findControlsByID($id));
3951
				}
3952
			}
3953
		}
3954
		return $controls;
3955
	}
3956
	public function clearNamingContainer()
3957
	{
3958
		unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
3959
		$this->clearNameTable();
3960
	}
3961
	public function registerObject($name,$object)
3962
	{
3963
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
3964
			throw new TInvalidOperationException('control_object_reregistered',$name);
3965
		$this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
3966
	}
3967
	public function unregisterObject($name)
3968
	{
3969
		unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
3970
	}
3971
	public function isObjectRegistered($name)
3972
	{
3973
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
3974
	}
3975
	public function getHasChildInitialized()
3976
	{
3977
		return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
3978
	}
3979
	public function getHasInitialized()
3980
	{
3981
		return $this->getControlStage() >= self::CS_INITIALIZED;
3982
	}
3983
	public function getHasLoadedPostData()
3984
	{
3985
		return $this->getControlStage() >= self::CS_STATE_LOADED;
3986
	}
3987
	public function getHasLoaded()
3988
	{
3989
		return $this->getControlStage() >= self::CS_LOADED;
3990
	}
3991
	public function getHasPreRendered()
3992
	{
3993
		return $this->getControlStage() >= self::CS_PRERENDERED;
3994
	}
3995
	public function getRegisteredObject($name)
3996
	{
3997
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
3998
	}
3999
	public function getAllowChildControls()
4000
	{
4001
		return true;
4002
	}
4003
	public function addParsedObject($object)
4004
	{
4005
		$this->getControls()->add($object);
4006
	}
4007
	final protected function clearChildState()
4008
	{
4009
		unset($this->_rf[self::RF_CHILD_STATE]);
4010
	}
4011
	final protected function isDescendentOf($ancestor)
4012
	{
4013
		$control=$this;
4014
		while($control!==$ancestor && $control->_parent)
4015
			$control=$control->_parent;
4016
		return $control===$ancestor;
4017
	}
4018
	public function addedControl($control)
4019
	{
4020
		if($control->_parent)
4021
			$control->_parent->getControls()->remove($control);
4022
		$control->_parent=$this;
4023
		$control->_page=$this->getPage();
4024
		$namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
4025
		if($namingContainer)
4026
		{
4027
			$control->_namingContainer=$namingContainer;
4028
			if($control->_id==='')
4029
				$control->generateAutomaticID();
4030
			else
4031
				$namingContainer->clearNameTable();
4032
			$control->clearCachedUniqueID($control instanceof INamingContainer);
4033
		}
4034
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
4035
		{
4036
			$control->initRecursive($namingContainer);
4037
			if($this->_stage>=self::CS_STATE_LOADED)
4038
			{
4039
				if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
4040
				{
4041
					$state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
4042
					unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
4043
				}
4044
				else
4045
					$state=null;
4046
				$control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
4047
				if($this->_stage>=self::CS_LOADED)
4048
				{
4049
					$control->loadRecursive();
4050
					if($this->_stage>=self::CS_PRERENDERED)
4051
						$control->preRenderRecursive();
4052
				}
4053
			}
4054
		}
4055
	}
4056
	public function removedControl($control)
4057
	{
4058
		if($this->_namingContainer)
4059
			$this->_namingContainer->clearNameTable();
4060
		$control->unloadRecursive();
4061
		$control->_parent=null;
4062
		$control->_page=null;
4063
		$control->_namingContainer=null;
4064
		$control->_tplControl=null;
4065
		if(!($control->_flags & self::IS_ID_SET))
4066
			$control->_id='';
4067
		else
4068
			unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
4069
		$control->clearCachedUniqueID(true);
4070
	}
4071
	protected function initRecursive($namingContainer=null)
4072
	{
4073
		$this->ensureChildControls();
4074
		if($this->getHasControls())
4075
		{
4076
			if($this instanceof INamingContainer)
4077
				$namingContainer=$this;
4078
			$page=$this->getPage();
4079
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4080
			{
4081
				if($control instanceof TControl)
4082
				{
4083
					$control->_namingContainer=$namingContainer;
4084
					$control->_page=$page;
4085
					if($control->_id==='' && $namingContainer)
4086
						$control->generateAutomaticID();
4087
					$control->initRecursive($namingContainer);
4088
				}
4089
			}
4090
		}
4091
		if($this->_stage<self::CS_INITIALIZED)
4092
		{
4093
			$this->_stage=self::CS_CHILD_INITIALIZED;
4094
			if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
4095
			{
4096
				$page->applyControlSkin($this);
4097
				$this->_flags |= self::IS_SKIN_APPLIED;
4098
			}
4099
			if(isset($this->_rf[self::RF_ADAPTER]))
4100
				$this->_rf[self::RF_ADAPTER]->onInit(null);
4101
			else
4102
				$this->onInit(null);
4103
			$this->_stage=self::CS_INITIALIZED;
4104
		}
4105
	}
4106
	protected function loadRecursive()
4107
	{
4108
		if($this->_stage<self::CS_LOADED)
4109
		{
4110
			if(isset($this->_rf[self::RF_ADAPTER]))
4111
				$this->_rf[self::RF_ADAPTER]->onLoad(null);
4112
			else
4113
				$this->onLoad(null);
4114
		}
4115
		if($this->getHasControls())
4116
		{
4117
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4118
			{
4119
				if($control instanceof TControl)
4120
					$control->loadRecursive();
4121
			}
4122
		}
4123
		if($this->_stage<self::CS_LOADED)
4124
			$this->_stage=self::CS_LOADED;
4125
	}
4126
	protected function preRenderRecursive()
4127
	{
4128
		$this->autoDataBindProperties();
4129
		if($this->getVisible(false))
4130
		{
4131
			if(isset($this->_rf[self::RF_ADAPTER]))
4132
				$this->_rf[self::RF_ADAPTER]->onPreRender(null);
4133
			else
4134
				$this->onPreRender(null);
4135
			if($this->getHasControls())
4136
			{
4137
				foreach($this->_rf[self::RF_CONTROLS] as $control)
4138
				{
4139
					if($control instanceof TControl)
4140
						$control->preRenderRecursive();
4141
					else if($control instanceof TCompositeLiteral)
4142
						$control->evaluateDynamicContent();
4143
				}
4144
			}
4145
			$this->addToPostDataLoader();
4146
		}
4147
		$this->_stage=self::CS_PRERENDERED;
4148
	}
4149
	protected function addToPostDataLoader()
4150
	{
4151
		if($this instanceof IPostBackDataHandler)
4152
			$this->getPage()->registerPostDataLoader($this);
4153
	}
4154
	protected function unloadRecursive()
4155
	{
4156
		if(!($this->_flags & self::IS_ID_SET))
4157
			$this->_id='';
4158
		if($this->getHasControls())
4159
		{
4160
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4161
				if($control instanceof TControl)
4162
					$control->unloadRecursive();
4163
		}
4164
		if(isset($this->_rf[self::RF_ADAPTER]))
4165
			$this->_rf[self::RF_ADAPTER]->onUnload(null);
4166
		else
4167
			$this->onUnload(null);
4168
	}
4169
	public function onInit($param)
4170
	{
4171
		$this->raiseEvent('OnInit',$this,$param);
4172
	}
4173
	public function onLoad($param)
4174
	{
4175
		$this->raiseEvent('OnLoad',$this,$param);
4176
	}
4177
	public function onDataBinding($param)
4178
	{
4179
		$this->raiseEvent('OnDataBinding',$this,$param);
4180
	}
4181
	public function onUnload($param)
4182
	{
4183
		$this->raiseEvent('OnUnload',$this,$param);
4184
	}
4185
	public function onPreRender($param)
4186
	{
4187
		$this->raiseEvent('OnPreRender',$this,$param);
4188
	}
4189
	protected function raiseBubbleEvent($sender,$param)
4190
	{
4191
		$control=$this;
4192
		while($control=$control->_parent)
4193
		{
4194
			if($control->bubbleEvent($sender,$param))
4195
				break;
4196
		}
4197
	}
4198
	public function bubbleEvent($sender,$param)
4199
	{
4200
		return false;
4201
	}
4202
	public function broadcastEvent($name,$sender,$param)
4203
	{
4204
		$rootControl=(($page=$this->getPage())===null)?$this:$page;
4205
		$rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
4206
	}
4207
	private function broadcastEventInternal($name,$sender,$param)
4208
	{
4209
		if($this->hasEvent($name))
4210
			$this->raiseEvent($name,$sender,$param->getParameter());
4211
		if($this instanceof IBroadcastEventReceiver)
4212
			$this->broadcastEventReceived($sender,$param);
4213
		if($this->getHasControls())
4214
		{
4215
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4216
			{
4217
				if($control instanceof TControl)
4218
					$control->broadcastEventInternal($name,$sender,$param);
4219
			}
4220
		}
4221
	}
4222
	protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
4223
	{
4224
		if($preCallback!==null)
4225
			call_user_func($preCallback,$this,$param);
4226
		if($this->getHasControls())
4227
		{
4228
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4229
			{
4230
				if($control instanceof TControl)
4231
				{
4232
					$control->traverseChildControls($param,$preCallback,$postCallback);
4233
				}
4234
			}
4235
		}
4236
		if($postCallback!==null)
4237
			call_user_func($postCallback,$this,$param);
4238
	}
4239
	public function renderControl($writer)
4240
	{
4241
		if($this->getVisible(false))
4242
		{
4243
			if(isset($this->_rf[self::RF_ADAPTER]))
4244
				$this->_rf[self::RF_ADAPTER]->render($writer);
4245
			else
4246
				$this->render($writer);
4247
		}
4248
	}
4249
	public function render($writer)
4250
	{
4251
		$this->renderChildren($writer);
4252
	}
4253
	public function renderChildren($writer)
4254
	{
4255
		if($this->getHasControls())
4256
		{
4257
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4258
			{
4259
				if(is_string($control))
4260
					$writer->write($control);
4261
				else if($control instanceof TControl)
4262
					$control->renderControl($writer);
4263
				else if($control instanceof IRenderable)
4264
					$control->render($writer);
4265
			}
4266
		}
4267
	}
4268
	public function saveState()
4269
	{
4270
	}
4271
	public function loadState()
4272
	{
4273
	}
4274
	protected function loadStateRecursive(&$state,$needViewState=true)
4275
	{
4276
		if(is_array($state))
4277
		{
4278
			$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
4279
			if(isset($state[1]))
4280
			{
4281
				$this->_rf[self::RF_CONTROLSTATE]=&$state[1];
4282
				unset($state[1]);
4283
			}
4284
			else
4285
				unset($this->_rf[self::RF_CONTROLSTATE]);
4286
			if($needViewState)
4287
			{
4288
				if(isset($state[0]))
4289
					$this->_viewState=&$state[0];
4290
				else
4291
					$this->_viewState=array();
4292
			}
4293
			unset($state[0]);
4294
			if($this->getHasControls())
4295
			{
4296
				foreach($this->_rf[self::RF_CONTROLS] as $control)
4297
				{
4298
					if($control instanceof TControl)
4299
					{
4300
						if(isset($state[$control->_id]))
4301
						{
4302
							$control->loadStateRecursive($state[$control->_id],$needViewState);
4303
							unset($state[$control->_id]);
4304
						}
4305
					}
4306
				}
4307
			}
4308
			if(!empty($state))
4309
				$this->_rf[self::RF_CHILD_STATE]=&$state;
4310
		}
4311
		$this->_stage=self::CS_STATE_LOADED;
4312
		if(isset($this->_rf[self::RF_ADAPTER]))
4313
			$this->_rf[self::RF_ADAPTER]->loadState();
4314
		else
4315
			$this->loadState();
4316
	}
4317
	protected function &saveStateRecursive($needViewState=true)
4318
	{
4319
		if(isset($this->_rf[self::RF_ADAPTER]))
4320
			$this->_rf[self::RF_ADAPTER]->saveState();
4321
		else
4322
			$this->saveState();
4323
		$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
4324
		$state=array();
4325
		if($this->getHasControls())
4326
		{
4327
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4328
			{
4329
				if($control instanceof TControl)
4330
					$state[$control->_id]=&$control->saveStateRecursive($needViewState);
4331
			}
4332
		}
4333
		if($needViewState && !empty($this->_viewState))
4334
			$state[0]=&$this->_viewState;
4335
		if(isset($this->_rf[self::RF_CONTROLSTATE]))
4336
			$state[1]=&$this->_rf[self::RF_CONTROLSTATE];
4337
		return $state;
4338
	}
4339
	public function applyStyleSheetSkin($page)
4340
	{
4341
		if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
4342
		{
4343
			$page->applyControlStyleSheet($this);
4344
			$this->_flags |= self::IS_STYLESHEET_APPLIED;
4345
		}
4346
		else if($this->_flags & self::IS_STYLESHEET_APPLIED)
4347
			throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
4348
	}
4349
	private function clearCachedUniqueID($recursive)
4350
	{
4351
		if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
4352
		{
4353
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4354
				if($control instanceof TControl)
4355
					$control->clearCachedUniqueID($recursive);
4356
		}
4357
		$this->_uid=null;
4358
	}
4359
	private function generateAutomaticID()
4360
	{
4361
		$this->_flags &= ~self::IS_ID_SET;
4362
		if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
4363
			$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
4364
		$id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
4365
		$this->_id=self::AUTOMATIC_ID_PREFIX . $id;
4366
		$this->_namingContainer->clearNameTable();
4367
	}
4368
	private function clearNameTable()
4369
	{
4370
		unset($this->_rf[self::RF_NAMED_CONTROLS]);
4371
	}
4372
	private function fillNameTable($container,$controls)
4373
	{
4374
		foreach($controls as $control)
4375
		{
4376
			if($control instanceof TControl)
4377
			{
4378
				if($control->_id!=='')
4379
				{
4380
					if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
4381
						throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
4382
					else
4383
						$container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
4384
				}
4385
				if(!($control instanceof INamingContainer) && $control->getHasControls())
4386
					$this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
4387
			}
4388
		}
4389
	}
4390
}
4391
class TControlCollection extends TList
4392
{
4393
	private $_o;
4394
	public function __construct(TControl $owner,$readOnly=false)
4395
	{
4396
		$this->_o=$owner;
4397
		parent::__construct(null,$readOnly);
4398
	}
4399
	protected function getOwner()
4400
	{
4401
		return $this->_o;
4402
	}
4403
	public function insertAt($index,$item)
4404
	{
4405
		if($item instanceof TControl)
4406
		{
4407
			parent::insertAt($index,$item);
4408
			$this->_o->addedControl($item);
4409
		}
4410
		else if(is_string($item) || ($item instanceof IRenderable))
4411
			parent::insertAt($index,$item);
4412
		else
4413
			throw new TInvalidDataTypeException('controlcollection_control_required');
4414
	}
4415
	public function removeAt($index)
4416
	{
4417
		$item=parent::removeAt($index);
4418
		if($item instanceof TControl)
4419
			$this->_o->removedControl($item);
4420
		return $item;
4421
	}
4422
	public function clear()
4423
	{
4424
		parent::clear();
4425
		if($this->_o instanceof INamingContainer)
4426
			$this->_o->clearNamingContainer();
4427
	}
4428
}
4429
class TEmptyControlCollection extends TControlCollection
4430
{
4431
	public function __construct(TControl $owner)
4432
	{
4433
		parent::__construct($owner,true);
4434
	}
4435
	public function insertAt($index,$item)
4436
	{
4437
		if(!is_string($item))
4438
			parent::insertAt($index,$item);
4439
	}
4440
}
4441
interface INamingContainer
4442
{
4443
}
4444
interface IPostBackEventHandler
4445
{
4446
	public function raisePostBackEvent($param);
4447
}
4448
interface IPostBackDataHandler
4449
{
4450
	public function loadPostData($key,$values);
4451
	public function raisePostDataChangedEvent();
4452
	public function getDataChanged();
4453
}
4454
interface IValidator
4455
{
4456
	public function validate();
4457
	public function getIsValid();
4458
	public function setIsValid($value);
4459
	public function getErrorMessage();
4460
	public function setErrorMessage($value);
4461
}
4462
interface IValidatable
4463
{
4464
	public function getValidationPropertyValue();
4465
	public function getIsValid();
4466
	public function setIsValid($value);
4467
}
4468
interface IBroadcastEventReceiver
4469
{
4470
	public function broadcastEventReceived($sender,$param);
4471
}
4472
interface ITheme
4473
{
4474
	public function applySkin($control);
4475
}
4476
interface ITemplate
4477
{
4478
	public function instantiateIn($parent);
4479
}
4480
interface IButtonControl
4481
{
4482
	public function getText();
4483
	public function setText($value);
4484
	public function getCausesValidation();
4485
	public function setCausesValidation($value);
4486
	public function getCommandName();
4487
	public function setCommandName($value);
4488
	public function getCommandParameter();
4489
	public function setCommandParameter($value);
4490
	public function getValidationGroup();
4491
	public function setValidationGroup($value);
4492
	public function onClick($param);
4493
	public function onCommand($param);
4494
	public function setIsDefaultButton($value);
4495
	public function getIsDefaultButton();
4496
}
4497
interface ISurroundable
4498
{
4499
	public function getSurroundingTagID();
4500
}
4501
class TBroadcastEventParameter extends TEventParameter
4502
{
4503
	private $_name;
4504
	private $_param;
4505
	public function __construct($name='',$parameter=null)
4506
	{
4507
		$this->_name=$name;
4508
		$this->_param=$parameter;
4509
	}
4510
	public function getName()
4511
	{
4512
		return $this->_name;
4513
	}
4514
	public function setName($value)
4515
	{
4516
		$this->_name=$value;
4517
	}
4518
	public function getParameter()
4519
	{
4520
		return $this->_param;
4521
	}
4522
	public function setParameter($value)
4523
	{
4524
		$this->_param=$value;
4525
	}
4526
}
4527
class TCommandEventParameter extends TEventParameter
4528
{
4529
	private $_name;
4530
	private $_param;
4531
	public function __construct($name='',$parameter='')
4532
	{
4533
		$this->_name=$name;
4534
		$this->_param=$parameter;
4535
	}
4536
	public function getCommandName()
4537
	{
4538
		return $this->_name;
4539
	}
4540
	public function getCommandParameter()
4541
	{
4542
		return $this->_param;
4543
	}
4544
}
4545
class TCompositeLiteral extends TComponent implements IRenderable, IBindable
4546
{
4547
	const TYPE_EXPRESSION=0;
4548
	const TYPE_STATEMENTS=1;
4549
	const TYPE_DATABINDING=2;
4550
	private $_container=null;
4551
	private $_items=array();
4552
	private $_expressions=array();
4553
	private $_statements=array();
4554
	private $_bindings=array();
4555
	public function __construct($items)
4556
	{
4557
		$this->_items=array();
4558
		$this->_expressions=array();
4559
		$this->_statements=array();
4560
		foreach($items as $id=>$item)
4561
		{
4562
			if(is_array($item))
4563
			{
4564
				if($item[0]===self::TYPE_EXPRESSION)
4565
					$this->_expressions[$id]=$item[1];
4566
				else if($item[0]===self::TYPE_STATEMENTS)
4567
					$this->_statements[$id]=$item[1];
4568
				else if($item[0]===self::TYPE_DATABINDING)
4569
					$this->_bindings[$id]=$item[1];
4570
				$this->_items[$id]='';
4571
			}
4572
			else
4573
				$this->_items[$id]=$item;
4574
		}
4575
	}
4576
	public function getContainer()
4577
	{
4578
		return $this->_container;
4579
	}
4580
	public function setContainer(TComponent $value)
4581
	{
4582
		$this->_container=$value;
4583
	}
4584
	public function evaluateDynamicContent()
4585
	{
4586
		$context=$this->_container===null?$this:$this->_container;
4587
		foreach($this->_expressions as $id=>$expression)
4588
			$this->_items[$id]=$context->evaluateExpression($expression);
4589
		foreach($this->_statements as $id=>$statement)
4590
			$this->_items[$id]=$context->evaluateStatements($statement);
4591
	}
4592
	public function dataBind()
4593
	{
4594
		$context=$this->_container===null?$this:$this->_container;
4595
		foreach($this->_bindings as $id=>$binding)
4596
			$this->_items[$id]=$context->evaluateExpression($binding);
4597
	}
4598
	public function render($writer)
4599
	{
4600
		$writer->write(implode('',$this->_items));
4601
	}
4602
}
4603
class TFont extends TComponent
4604
{
4605
	const IS_BOLD=0x01;
4606
	const IS_ITALIC=0x02;
4607
	const IS_OVERLINE=0x04;
4608
	const IS_STRIKEOUT=0x08;
4609
	const IS_UNDERLINE=0x10;
4610
	const IS_SET_BOLD=0x01000;
4611
	const IS_SET_ITALIC=0x02000;
4612
	const IS_SET_OVERLINE=0x04000;
4613
	const IS_SET_STRIKEOUT=0x08000;
4614
	const IS_SET_UNDERLINE=0x10000;
4615
	const IS_SET_SIZE=0x20000;
4616
	const IS_SET_NAME=0x40000;
4617
	private $_flags=0;
4618
	private $_name='';
4619
	private $_size='';
4620
	public function getBold()
4621
	{
4622
		return ($this->_flags & self::IS_BOLD)!==0;
4623
	}
4624
	public function setBold($value)
4625
	{
4626
		$this->_flags |= self::IS_SET_BOLD;
4627
		if(TPropertyValue::ensureBoolean($value))
4628
			$this->_flags |= self::IS_BOLD;
4629
		else
4630
			$this->_flags &= ~self::IS_BOLD;
4631
	}
4632
	public function getItalic()
4633
	{
4634
		return ($this->_flags & self::IS_ITALIC)!==0;
4635
	}
4636
	public function setItalic($value)
4637
	{
4638
		$this->_flags |= self::IS_SET_ITALIC;
4639
		if(TPropertyValue::ensureBoolean($value))
4640
			$this->_flags |= self::IS_ITALIC;
4641
		else
4642
			$this->_flags &= ~self::IS_ITALIC;
4643
	}
4644
	public function getOverline()
4645
	{
4646
		return ($this->_flags & self::IS_OVERLINE)!==0;
4647
	}
4648
	public function setOverline($value)
4649
	{
4650
		$this->_flags |= self::IS_SET_OVERLINE;
4651
		if(TPropertyValue::ensureBoolean($value))
4652
			$this->_flags |= self::IS_OVERLINE;
4653
		else
4654
			$this->_flags &= ~self::IS_OVERLINE;
4655
	}
4656
	public function getSize()
4657
	{
4658
		return $this->_size;
4659
	}
4660
	public function setSize($value)
4661
	{
4662
		$this->_flags |= self::IS_SET_SIZE;
4663
		$this->_size=$value;
4664
	}
4665
	public function getStrikeout()
4666
	{
4667
		return ($this->_flags & self::IS_STRIKEOUT)!==0;
4668
	}
4669
	public function setStrikeout($value)
4670
	{
4671
		$this->_flags |= self::IS_SET_STRIKEOUT;
4672
		if(TPropertyValue::ensureBoolean($value))
4673
			$this->_flags |= self::IS_STRIKEOUT;
4674
		else
4675
			$this->_flags &= ~self::IS_STRIKEOUT;
4676
	}
4677
	public function getUnderline()
4678
	{
4679
		return ($this->_flags & self::IS_UNDERLINE)!==0;
4680
	}
4681
	public function setUnderline($value)
4682
	{
4683
		$this->_flags |= self::IS_SET_UNDERLINE;
4684
		if(TPropertyValue::ensureBoolean($value))
4685
			$this->_flags |= self::IS_UNDERLINE;
4686
		else
4687
			$this->_flags &= ~self::IS_UNDERLINE;
4688
	}
4689
	public function getName()
4690
	{
4691
		return $this->_name;
4692
	}
4693
	public function setName($value)
4694
	{
4695
		$this->_flags |= self::IS_SET_NAME;
4696
		$this->_name=$value;
4697
	}
4698
	public function getIsEmpty()
4699
	{
4700
		return !$this->_flags;
4701
	}
4702
	public function reset()
4703
	{
4704
		$this->_flags=0;
4705
		$this->_name='';
4706
		$this->_size='';
4707
	}
4708
	public function mergeWith($font)
4709
	{
4710
		if($font===null || $font->_flags===0)
4711
			return;
4712
		if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
4713
			$this->setBold($font->getBold());
4714
		if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
4715
			$this->setItalic($font->getItalic());
4716
		if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
4717
			$this->setOverline($font->getOverline());
4718
		if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
4719
			$this->setStrikeout($font->getStrikeout());
4720
		if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
4721
			$this->setUnderline($font->getUnderline());
4722
		if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
4723
			$this->setSize($font->getSize());
4724
		if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
4725
			$this->setName($font->getName());
4726
	}
4727
	public function copyFrom($font)
4728
	{
4729
		if($font===null || $font->_flags===0)
4730
			return;
4731
		if($font->_flags & self::IS_SET_BOLD)
4732
			$this->setBold($font->getBold());
4733
		if($font->_flags & self::IS_SET_ITALIC)
4734
			$this->setItalic($font->getItalic());
4735
		if($font->_flags & self::IS_SET_OVERLINE)
4736
			$this->setOverline($font->getOverline());
4737
		if($font->_flags & self::IS_SET_STRIKEOUT)
4738
			$this->setStrikeout($font->getStrikeout());
4739
		if($font->_flags & self::IS_SET_UNDERLINE)
4740
			$this->setUnderline($font->getUnderline());
4741
		if($font->_flags & self::IS_SET_SIZE)
4742
			$this->setSize($font->getSize());
4743
		if($font->_flags & self::IS_SET_NAME)
4744
			$this->setName($font->getName());
4745
	}
4746
	public function toString()
4747
	{
4748
		if($this->_flags===0)
4749
			return '';
4750
		$str='';
4751
		if($this->_flags & self::IS_SET_BOLD)
4752
			$str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
4753
		if($this->_flags & self::IS_SET_ITALIC)
4754
			$str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
4755
		$textDec='';
4756
		if($this->_flags & self::IS_UNDERLINE)
4757
			$textDec.='underline';
4758
		if($this->_flags & self::IS_OVERLINE)
4759
			$textDec.=' overline';
4760
		if($this->_flags & self::IS_STRIKEOUT)
4761
			$textDec.=' line-through';
4762
		$textDec=ltrim($textDec);
4763
		if($textDec!=='')
4764
			$str.='text-decoration:'.$textDec.';';
4765
		if($this->_size!=='')
4766
			$str.='font-size:'.$this->_size.';';
4767
		if($this->_name!=='')
4768
			$str.='font-family:'.$this->_name.';';
4769
		return $str;
4770
	}
4771
	public function addAttributesToRender($writer)
4772
	{
4773
		if($this->_flags===0)
4774
			return;
4775
		if($this->_flags & self::IS_SET_BOLD)
4776
			$writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
4777
		if($this->_flags & self::IS_SET_ITALIC)
4778
			$writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
4779
		$textDec='';
4780
		if($this->_flags & self::IS_UNDERLINE)
4781
			$textDec.='underline';
4782
		if($this->_flags & self::IS_OVERLINE)
4783
			$textDec.=' overline';
4784
		if($this->_flags & self::IS_STRIKEOUT)
4785
			$textDec.=' line-through';
4786
		$textDec=ltrim($textDec);
4787
		if($textDec!=='')
4788
			$writer->addStyleAttribute('text-decoration',$textDec);
4789
		if($this->_size!=='')
4790
			$writer->addStyleAttribute('font-size',$this->_size);
4791
		if($this->_name!=='')
4792
			$writer->addStyleAttribute('font-family',$this->_name);
4793
	}
4794
}
4795
class TStyle extends TComponent
4796
{
4797
	private $_fields=array();
4798
	private $_font=null;
4799
	private $_class=null;
4800
	private $_customStyle=null;
4801
	private $_displayStyle='Fixed';
4802
	public function __construct($style=null)
4803
	{
4804
		if($style!==null)
4805
			$this->copyFrom($style);
4806
	}
4807
	public function __clone()
4808
	{
4809
		if(!is_null($this->_font))
4810
			$this->_font = clone($this->_font);
4811
	}
4812
	public function getBackColor()
4813
	{
4814
		return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
4815
	}
4816
	public function setBackColor($value)
4817
	{
4818
		if(trim($value)==='')
4819
			unset($this->_fields['background-color']);
4820
		else
4821
			$this->_fields['background-color']=$value;
4822
	}
4823
	public function getBorderColor()
4824
	{
4825
		return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
4826
	}
4827
	public function setBorderColor($value)
4828
	{
4829
		if(trim($value)==='')
4830
			unset($this->_fields['border-color']);
4831
		else
4832
			$this->_fields['border-color']=$value;
4833
	}
4834
	public function getBorderStyle()
4835
	{
4836
		return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
4837
	}
4838
	public function setBorderStyle($value)
4839
	{
4840
		if(trim($value)==='')
4841
			unset($this->_fields['border-style']);
4842
		else
4843
			$this->_fields['border-style']=$value;
4844
	}
4845
	public function getBorderWidth()
4846
	{
4847
		return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
4848
	}
4849
	public function setBorderWidth($value)
4850
	{
4851
		if(trim($value)==='')
4852
			unset($this->_fields['border-width']);
4853
		else
4854
			$this->_fields['border-width']=$value;
4855
	}
4856
	public function getCssClass()
4857
	{
4858
		return $this->_class===null?'':$this->_class;
4859
	}
4860
	public function hasCssClass()
4861
	{
4862
		return !is_null($this->_class);
4863
	}
4864
	public function setCssClass($value)
4865
	{
4866
		$this->_class=$value;
4867
	}
4868
	public function getFont()
4869
	{
4870
		if($this->_font===null)
4871
			$this->_font=new TFont;
4872
		return $this->_font;
4873
	}
4874
	public function hasFont()
4875
	{
4876
		return $this->_font !== null;
4877
	}
4878
	public function setDisplayStyle($value)
4879
	{
4880
		$this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
4881
		switch($this->_displayStyle)
4882
		{
4883
			case TDisplayStyle::None:
4884
				$this->_fields['display'] = 'none';
4885
				break;
4886
			case TDisplayStyle::Dynamic:
4887
				$this->_fields['display'] = '';
4888
				break;
4889
			case TDisplayStyle::Fixed:
4890
				$this->_fields['visibility'] = 'visible';
4891
				break;
4892
			case TDisplayStyle::Hidden:
4893
				$this->_fields['visibility'] = 'hidden';
4894
				break;
4895
		}
4896
	}
4897
	public function getDisplayStyle()
4898
	{
4899
		return $this->_displayStyle;
4900
	}
4901
	public function getForeColor()
4902
	{
4903
		return isset($this->_fields['color'])?$this->_fields['color']:'';
4904
	}
4905
	public function setForeColor($value)
4906
	{
4907
		if(trim($value)==='')
4908
			unset($this->_fields['color']);
4909
		else
4910
			$this->_fields['color']=$value;
4911
	}
4912
	public function getHeight()
4913
	{
4914
		return isset($this->_fields['height'])?$this->_fields['height']:'';
4915
	}
4916
	public function setHeight($value)
4917
	{
4918
		if(trim($value)==='')
4919
			unset($this->_fields['height']);
4920
		else
4921
			$this->_fields['height']=$value;
4922
	}
4923
	public function getCustomStyle()
4924
	{
4925
		return $this->_customStyle===null?'':$this->_customStyle;
4926
	}
4927
	public function setCustomStyle($value)
4928
	{
4929
		$this->_customStyle=$value;
4930
	}
4931
	public function getStyleField($name)
4932
	{
4933
		return isset($this->_fields[$name])?$this->_fields[$name]:'';
4934
	}
4935
	public function setStyleField($name,$value)
4936
	{
4937
		$this->_fields[$name]=$value;
4938
	}
4939
	public function clearStyleField($name)
4940
	{
4941
		unset($this->_fields[$name]);
4942
	}
4943
	public function hasStyleField($name)
4944
	{
4945
		return isset($this->_fields[$name]);
4946
	}
4947
	public function getWidth()
4948
	{
4949
		return isset($this->_fields['width'])?$this->_fields['width']:'';
4950
	}
4951
	public function setWidth($value)
4952
	{
4953
		$this->_fields['width']=$value;
4954
	}
4955
	public function reset()
4956
	{
4957
		$this->_fields=array();
4958
		$this->_font=null;
4959
		$this->_class=null;
4960
		$this->_customStyle=null;
4961
	}
4962
	public function copyFrom($style)
4963
	{
4964
		if($style instanceof TStyle)
4965
		{
4966
			$this->_fields=array_merge($this->_fields,$style->_fields);
4967
			if($style->_class!==null)
4968
				$this->_class=$style->_class;
4969
			if($style->_customStyle!==null)
4970
				$this->_customStyle=$style->_customStyle;
4971
			if($style->_font!==null)
4972
				$this->getFont()->copyFrom($style->_font);
4973
		}
4974
	}
4975
	public function mergeWith($style)
4976
	{
4977
		if($style instanceof TStyle)
4978
		{
4979
			$this->_fields=array_merge($style->_fields,$this->_fields);
4980
			if($this->_class===null)
4981
				$this->_class=$style->_class;
4982
			if($this->_customStyle===null)
4983
				$this->_customStyle=$style->_customStyle;
4984
			if($style->_font!==null)
4985
				$this->getFont()->mergeWith($style->_font);
4986
		}
4987
	}
4988
	public function addAttributesToRender($writer)
4989
	{
4990
		if($this->_customStyle!==null)
4991
		{
4992
			foreach(explode(';',$this->_customStyle) as $style)
4993
			{
4994
				$arr=explode(':',$style);
4995
				if(isset($arr[1]) && trim($arr[0])!=='')
4996
					$writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
4997
			}
4998
		}
4999
		$writer->addStyleAttributes($this->_fields);
5000
		if($this->_font!==null)
5001
			$this->_font->addAttributesToRender($writer);
5002
		if($this->_class!==null)
5003
			$writer->addAttribute('class',$this->_class);
5004
	}
5005
	public function getStyleFields()
5006
	{
5007
		return $this->_fields;
5008
	}
5009
}
5010
class TDisplayStyle extends TEnumerable
5011
{
5012
	const None='None';
5013
	const Dynamic='Dynamic';
5014
	const Fixed='Fixed';
5015
	const Hidden='Hidden';
5016
}
5017
class TTableStyle extends TStyle
5018
{
5019
	private $_backImageUrl=null;
5020
	private $_horizontalAlign=null;
5021
	private $_cellPadding=null;
5022
	private $_cellSpacing=null;
5023
	private $_gridLines=null;
5024
	private $_borderCollapse=null;
5025
	public function reset()
5026
	{
5027
		$this->_backImageUrl=null;
5028
		$this->_horizontalAlign=null;
5029
		$this->_cellPadding=null;
5030
		$this->_cellSpacing=null;
5031
		$this->_gridLines=null;
5032
		$this->_borderCollapse=null;
5033
	}
5034
	public function copyFrom($style)
5035
	{
5036
		parent::copyFrom($style);
5037
		if($style instanceof TTableStyle)
5038
		{
5039
			if($style->_backImageUrl!==null)
5040
				$this->_backImageUrl=$style->_backImageUrl;
5041
			if($style->_horizontalAlign!==null)
5042
				$this->_horizontalAlign=$style->_horizontalAlign;
5043
			if($style->_cellPadding!==null)
5044
				$this->_cellPadding=$style->_cellPadding;
5045
			if($style->_cellSpacing!==null)
5046
				$this->_cellSpacing=$style->_cellSpacing;
5047
			if($style->_gridLines!==null)
5048
				$this->_gridLines=$style->_gridLines;
5049
			if($style->_borderCollapse!==null)
5050
				$this->_borderCollapse=$style->_borderCollapse;
5051
		}
5052
	}
5053
	public function mergeWith($style)
5054
	{
5055
		parent::mergeWith($style);
5056
		if($style instanceof TTableStyle)
5057
		{
5058
			if($this->_backImageUrl===null && $style->_backImageUrl!==null)
5059
				$this->_backImageUrl=$style->_backImageUrl;
5060
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
5061
				$this->_horizontalAlign=$style->_horizontalAlign;
5062
			if($this->_cellPadding===null && $style->_cellPadding!==null)
5063
				$this->_cellPadding=$style->_cellPadding;
5064
			if($this->_cellSpacing===null && $style->_cellSpacing!==null)
5065
				$this->_cellSpacing=$style->_cellSpacing;
5066
			if($this->_gridLines===null && $style->_gridLines!==null)
5067
				$this->_gridLines=$style->_gridLines;
5068
			if($this->_borderCollapse===null && $style->_borderCollapse!==null)
5069
				$this->_borderCollapse=$style->_borderCollapse;
5070
		}
5071
	}
5072
	public function addAttributesToRender($writer)
5073
	{
5074
		if(($url=trim($this->getBackImageUrl()))!=='')
5075
			$writer->addStyleAttribute('background-image','url('.$url.')');
5076
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
5077
			$writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
5078
		if(($cellPadding=$this->getCellPadding())>=0)
5079
			$writer->addAttribute('cellpadding',"$cellPadding");
5080
		if(($cellSpacing=$this->getCellSpacing())>=0)
5081
			$writer->addAttribute('cellspacing',"$cellSpacing");
5082
		if($this->getBorderCollapse())
5083
			$writer->addStyleAttribute('border-collapse','collapse');
5084
		switch($this->getGridLines())
5085
		{
5086
			case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
5087
			case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
5088
			case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
5089
		}
5090
		parent::addAttributesToRender($writer);
5091
	}
5092
	public function getBackImageUrl()
5093
	{
5094
		return $this->_backImageUrl===null?'':$this->_backImageUrl;
5095
	}
5096
	public function setBackImageUrl($value)
5097
	{
5098
		$this->_backImageUrl=$value;
5099
	}
5100
	public function getHorizontalAlign()
5101
	{
5102
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
5103
	}
5104
	public function setHorizontalAlign($value)
5105
	{
5106
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
5107
	}
5108
	public function getCellPadding()
5109
	{
5110
		return $this->_cellPadding===null?-1:$this->_cellPadding;
5111
	}
5112
	public function setCellPadding($value)
5113
	{
5114
		if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
5115
			throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
5116
	}
5117
	public function getCellSpacing()
5118
	{
5119
		return $this->_cellSpacing===null?-1:$this->_cellSpacing;
5120
	}
5121
	public function setCellSpacing($value)
5122
	{
5123
		if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
5124
			throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
5125
	}
5126
	public function getGridLines()
5127
	{
5128
		return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
5129
	}
5130
	public function setGridLines($value)
5131
	{
5132
		$this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
5133
	}
5134
	public function getBorderCollapse()
5135
	{
5136
		return $this->_borderCollapse===null?false:$this->_borderCollapse;
5137
	}
5138
	public function setBorderCollapse($value)
5139
	{
5140
		$this->_borderCollapse=TPropertyValue::ensureBoolean($value);
5141
	}
5142
}
5143
class TTableItemStyle extends TStyle
5144
{
5145
	private $_horizontalAlign=null;
5146
	private $_verticalAlign=null;
5147
	private $_wrap=null;
5148
	public function reset()
5149
	{
5150
		parent::reset();
5151
		$this->_verticalAlign=null;
5152
		$this->_horizontalAlign=null;
5153
		$this->_wrap=null;
5154
	}
5155
	public function copyFrom($style)
5156
	{
5157
		parent::copyFrom($style);
5158
		if($style instanceof TTableItemStyle)
5159
		{
5160
			if($this->_verticalAlign===null && $style->_verticalAlign!==null)
5161
				$this->_verticalAlign=$style->_verticalAlign;
5162
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
5163
				$this->_horizontalAlign=$style->_horizontalAlign;
5164
			if($this->_wrap===null && $style->_wrap!==null)
5165
				$this->_wrap=$style->_wrap;
5166
		}
5167
	}
5168
	public function mergeWith($style)
5169
	{
5170
		parent::mergeWith($style);
5171
		if($style instanceof TTableItemStyle)
5172
		{
5173
			if($style->_verticalAlign!==null)
5174
				$this->_verticalAlign=$style->_verticalAlign;
5175
			if($style->_horizontalAlign!==null)
5176
				$this->_horizontalAlign=$style->_horizontalAlign;
5177
			if($style->_wrap!==null)
5178
				$this->_wrap=$style->_wrap;
5179
		}
5180
	}
5181
	public function addAttributesToRender($writer)
5182
	{
5183
		if(!$this->getWrap())
5184
			$writer->addStyleAttribute('white-space','nowrap');
5185
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
5186
			$writer->addAttribute('align',strtolower($horizontalAlign));
5187
		if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
5188
			$writer->addAttribute('valign',strtolower($verticalAlign));
5189
		parent::addAttributesToRender($writer);
5190
	}
5191
	public function getHorizontalAlign()
5192
	{
5193
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
5194
	}
5195
	public function setHorizontalAlign($value)
5196
	{
5197
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
5198
	}
5199
	public function getVerticalAlign()
5200
	{
5201
		return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
5202
	}
5203
	public function setVerticalAlign($value)
5204
	{
5205
		$this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
5206
	}
5207
	public function getWrap()
5208
	{
5209
		return $this->_wrap===null?true:$this->_wrap;
5210
	}
5211
	public function setWrap($value)
5212
	{
5213
		$this->_wrap=TPropertyValue::ensureBoolean($value);
5214
	}
5215
}
5216
class THorizontalAlign extends TEnumerable
5217
{
5218
	const NotSet='NotSet';
5219
	const Left='Left';
5220
	const Right='Right';
5221
	const Center='Center';
5222
	const Justify='Justify';
5223
}
5224
class TVerticalAlign extends TEnumerable
5225
{
5226
	const NotSet='NotSet';
5227
	const Top='Top';
5228
	const Bottom='Bottom';
5229
	const Middle='Middle';
5230
}
5231
class TTableGridLines extends TEnumerable
5232
{
5233
	const None='None';
5234
	const Horizontal='Horizontal';
5235
	const Vertical='Vertical';
5236
	const Both='Both';
5237
}
5238
class TWebControlAdapter extends TControlAdapter
5239
{
5240
	public function render($writer)
5241
	{
5242
		$this->renderBeginTag($writer);
5243
		$this->renderContents($writer);
5244
		$this->renderEndTag($writer);
5245
	}
5246
	public function renderBeginTag($writer)
5247
	{
5248
		$this->getControl()->renderBeginTag($writer);
5249
	}
5250
	public function renderContents($writer)
5251
	{
5252
		$this->getControl()->renderContents($writer);
5253
	}
5254
	public function renderEndTag($writer)
5255
	{
5256
		$this->getControl()->renderEndTag($writer);
5257
	}
5258
}
5259
class TWebControl extends TControl implements IStyleable
5260
{
5261
	public function copyBaseAttributes(TWebControl $control)
5262
	{
5263
		$this->setAccessKey($control->getAccessKey());
5264
		$this->setToolTip($control->getToolTip());
5265
		$this->setTabIndex($control->getTabIndex());
5266
		if(!$control->getEnabled())
5267
			$this->setEnabled(false);
5268
		if($control->getHasAttributes())
5269
			$this->getAttributes()->copyFrom($control->getAttributes());
5270
	}
5271
	public function getAccessKey()
5272
	{
5273
		return $this->getViewState('AccessKey','');
5274
	}
5275
	public function setAccessKey($value)
5276
	{
5277
		if(strlen($value)>1)
5278
			throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
5279
		$this->setViewState('AccessKey',$value,'');
5280
	}
5281
	public function getBackColor()
5282
	{
5283
		if($style=$this->getViewState('Style',null))
5284
			return $style->getBackColor();
5285
		else
5286
			return '';
5287
	}
5288
	public function setBackColor($value)
5289
	{
5290
		$this->getStyle()->setBackColor($value);
5291
	}
5292
	public function getBorderColor()
5293
	{
5294
		if($style=$this->getViewState('Style',null))
5295
			return $style->getBorderColor();
5296
		else
5297
			return '';
5298
	}
5299
	public function setBorderColor($value)
5300
	{
5301
		$this->getStyle()->setBorderColor($value);
5302
	}
5303
	public function getBorderStyle()
5304
	{
5305
		if($style=$this->getViewState('Style',null))
5306
			return $style->getBorderStyle();
5307
		else
5308
			return '';
5309
	}
5310
	public function setBorderStyle($value)
5311
	{
5312
		$this->getStyle()->setBorderStyle($value);
5313
	}
5314
	public function getBorderWidth()
5315
	{
5316
		if($style=$this->getViewState('Style',null))
5317
			return $style->getBorderWidth();
5318
		else
5319
			return '';
5320
	}
5321
	public function setBorderWidth($value)
5322
	{
5323
		$this->getStyle()->setBorderWidth($value);
5324
	}
5325
	public function getFont()
5326
	{
5327
		return $this->getStyle()->getFont();
5328
	}
5329
	public function getForeColor()
5330
	{
5331
		if($style=$this->getViewState('Style',null))
5332
			return $style->getForeColor();
5333
		else
5334
			return '';
5335
	}
5336
	public function setForeColor($value)
5337
	{
5338
		$this->getStyle()->setForeColor($value);
5339
	}
5340
	public function getHeight()
5341
	{
5342
		if($style=$this->getViewState('Style',null))
5343
			return $style->getHeight();
5344
		else
5345
			return '';
5346
	}
5347
	public function setDisplay($value)
5348
	{
5349
		$this->getStyle()->setDisplayStyle($value);
5350
	}
5351
	public function getDisplay()
5352
	{
5353
		return $this->getStyle()->getDisplayStyle();
5354
	}
5355
	public function setCssClass($value)
5356
	{
5357
		$this->getStyle()->setCssClass($value);
5358
	}
5359
	public function getCssClass()
5360
	{
5361
		if($style=$this->getViewState('Style',null))
5362
			return $style->getCssClass();
5363
		else
5364
			return '';
5365
	}
5366
	public function setHeight($value)
5367
	{
5368
		$this->getStyle()->setHeight($value);
5369
	}
5370
	public function getHasStyle()
5371
	{
5372
		return $this->getViewState('Style',null)!==null;
5373
	}
5374
	protected function createStyle()
5375
	{
5376
		return new TStyle;
5377
	}
5378
	public function getStyle()
5379
	{
5380
		if($style=$this->getViewState('Style',null))
5381
			return $style;
5382
		else
5383
		{
5384
			$style=$this->createStyle();
5385
			$this->setViewState('Style',$style,null);
5386
			return $style;
5387
		}
5388
	}
5389
	public function setStyle($value)
5390
	{
5391
		if(is_string($value))
5392
			$this->getStyle()->setCustomStyle($value);
5393
		else
5394
			throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
5395
	}
5396
	public function clearStyle()
5397
	{
5398
		$this->clearViewState('Style');
5399
	}
5400
	public function getTabIndex()
5401
	{
5402
		return $this->getViewState('TabIndex',0);
5403
	}
5404
	public function setTabIndex($value)
5405
	{
5406
		$this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
5407
	}
5408
	protected function getTagName()
5409
	{
5410
		return 'span';
5411
	}
5412
	public function getToolTip()
5413
	{
5414
		return $this->getViewState('ToolTip','');
5415
	}
5416
	public function setToolTip($value)
5417
	{
5418
		$this->setViewState('ToolTip',$value,'');
5419
	}
5420
	public function getWidth()
5421
	{
5422
		if($style=$this->getViewState('Style',null))
5423
			return $style->getWidth();
5424
		else
5425
			return '';
5426
	}
5427
	public function setWidth($value)
5428
	{
5429
		$this->getStyle()->setWidth($value);
5430
	}
5431
	protected function addAttributesToRender($writer)
5432
	{
5433
		if($this->getID()!=='')
5434
			$writer->addAttribute('id',$this->getClientID());
5435
		if(($accessKey=$this->getAccessKey())!=='')
5436
			$writer->addAttribute('accesskey',$accessKey);
5437
		if(!$this->getEnabled())
5438
			$writer->addAttribute('disabled','disabled');
5439
		if(($tabIndex=$this->getTabIndex())>0)
5440
			$writer->addAttribute('tabindex',"$tabIndex");
5441
		if(($toolTip=$this->getToolTip())!=='')
5442
			$writer->addAttribute('title',$toolTip);
5443
		if($style=$this->getViewState('Style',null))
5444
			$style->addAttributesToRender($writer);
5445
		if($this->getHasAttributes())
5446
		{
5447
			foreach($this->getAttributes() as $name=>$value)
5448
				$writer->addAttribute($name,$value);
5449
		}
5450
	}
5451
	public function render($writer)
5452
	{
5453
		$this->renderBeginTag($writer);
5454
		$this->renderContents($writer);
5455
		$this->renderEndTag($writer);
5456
	}
5457
	public function renderBeginTag($writer)
5458
	{
5459
		$this->addAttributesToRender($writer);
5460
		$writer->renderBeginTag($this->getTagName());
5461
	}
5462
	public function renderContents($writer)
5463
	{
5464
		parent::renderChildren($writer);
5465
	}
5466
	public function renderEndTag($writer)
5467
	{
5468
		$writer->renderEndTag();
5469
	}
5470
}
5471
class TCompositeControl extends TControl implements INamingContainer
5472
{
5473
	protected function initRecursive($namingContainer=null)
5474
	{
5475
		$this->ensureChildControls();
5476
		parent::initRecursive($namingContainer);
5477
	}
5478
}
5479
class TTemplateControl extends TCompositeControl
5480
{
5481
	const EXT_TEMPLATE='.tpl';
5482
	private static $_template=array();
5483
	private $_localTemplate=null;
5484
	private $_master=null;
5485
	private $_masterClass='';
5486
	private $_contents=array();
5487
	private $_placeholders=array();
5488
	public function getTemplate()
5489
	{
5490
		if($this->_localTemplate===null)
5491
		{
5492
			$class=get_class($this);
5493
			if(!isset(self::$_template[$class]))
5494
				self::$_template[$class]=$this->loadTemplate();
5495
			return self::$_template[$class];
5496
		}
5497
		else
5498
			return $this->_localTemplate;
5499
	}
5500
	public function setTemplate($value)
5501
	{
5502
		$this->_localTemplate=$value;
5503
	}
5504
	public function getIsSourceTemplateControl()
5505
	{
5506
		if(($template=$this->getTemplate())!==null)
5507
			return $template->getIsSourceTemplate();
5508
		else
5509
			return false;
5510
	}
5511
	public function getTemplateDirectory()
5512
	{
5513
		if(($template=$this->getTemplate())!==null)
5514
			return $template->getContextPath();
5515
		else
5516
			return '';
5517
	}
5518
	protected function loadTemplate()
5519
	{
5520
		$template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
5521
		return $template;
5522
	}
5523
	public function createChildControls()
5524
	{
5525
		if($tpl=$this->getTemplate())
5526
		{
5527
			foreach($tpl->getDirective() as $name=>$value)
5528
			{
5529
				if(is_string($value))
5530
					$this->setSubProperty($name,$value);
5531
				else
5532
					throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
5533
			}
5534
			$tpl->instantiateIn($this);
5535
		}
5536
	}
5537
	public function registerContent($id,TContent $object)
5538
	{
5539
		if(isset($this->_contents[$id]))
5540
			throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
5541
		else
5542
			$this->_contents[$id]=$object;
5543
	}
5544
	public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
5545
	{
5546
		if(isset($this->_placeholders[$id]))
5547
			throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
5548
		else
5549
			$this->_placeholders[$id]=$object;
5550
	}
5551
	public function getMasterClass()
5552
	{
5553
		return $this->_masterClass;
5554
	}
5555
	public function setMasterClass($value)
5556
	{
5557
		$this->_masterClass=$value;
5558
	}
5559
	public function getMaster()
5560
	{
5561
		return $this->_master;
5562
	}
5563
	public function injectContent($id,$content)
5564
	{
5565
		if(isset($this->_placeholders[$id]))
5566
		{
5567
			$placeholder=$this->_placeholders[$id];
5568
			$controls=$placeholder->getParent()->getControls();
5569
			$loc=$controls->remove($placeholder);
5570
			$controls->insertAt($loc,$content);
5571
		}
5572
		else
5573
			throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
5574
	}
5575
	protected function initRecursive($namingContainer=null)
5576
	{
5577
		$this->ensureChildControls();
5578
		if($this->_masterClass!=='')
5579
		{
5580
			$master=Prado::createComponent($this->_masterClass);
5581
			if(!($master instanceof TTemplateControl))
5582
				throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
5583
			$this->_master=$master;
5584
			$this->getControls()->clear();
5585
			$this->getControls()->add($master);
5586
			$master->ensureChildControls();
5587
			foreach($this->_contents as $id=>$content)
5588
				$master->injectContent($id,$content);
5589
		}
5590
		else if(!empty($this->_contents))
5591
			throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
5592
		parent::initRecursive($namingContainer);
5593
	}
5594
}
5595
class TForm extends TControl
5596
{
5597
	public function onInit($param)
5598
	{
5599
		parent::onInit($param);
5600
		$this->getPage()->setForm($this);
5601
	}
5602
	protected function addAttributesToRender($writer)
5603
	{
5604
		$writer->addAttribute('id',$this->getClientID());
5605
		$writer->addAttribute('method',$this->getMethod());
5606
		$uri=$this->getRequest()->getRequestURI();
5607
		$writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
5608
		if(($enctype=$this->getEnctype())!=='')
5609
			$writer->addAttribute('enctype',$enctype);
5610
		$attributes=$this->getAttributes();
5611
		$attributes->remove('action');
5612
		$writer->addAttributes($attributes);
5613
		if(($butt=$this->getDefaultButton())!=='')
5614
		{
5615
			if(($button=$this->findControl($butt))!==null)
5616
				$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
5617
			else
5618
				throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
5619
		}
5620
	}
5621
	public function render($writer)
5622
	{
5623
		$page=$this->getPage();
5624
		$page->beginFormRender($writer);
5625
		$textWriter=new TTextWriter;
5626
		$this->renderChildren(new THtmlWriter($textWriter));
5627
		$content=$textWriter->flush();
5628
		$page->endFormRender($writer);
5629
		$this->addAttributesToRender($writer);
5630
		$writer->renderBeginTag('form');
5631
		$cs=$page->getClientScript();
5632
		if($page->getClientSupportsJavaScript())
5633
		{
5634
			$cs->renderHiddenFields($writer);
5635
			$cs->renderScriptFiles($writer);
5636
			$cs->renderBeginScripts($writer);
5637
			$writer->write($content);
5638
			$cs->renderEndScripts($writer);
5639
		}
5640
		else
5641
		{
5642
			$cs->renderHiddenFields($writer);
5643
			$writer->write($content);
5644
		}
5645
		$writer->renderEndTag();
5646
	}
5647
	public function getDefaultButton()
5648
	{
5649
		return $this->getViewState('DefaultButton','');
5650
	}
5651
	public function setDefaultButton($value)
5652
	{
5653
		$this->setViewState('DefaultButton',$value,'');
5654
	}
5655
	public function getMethod()
5656
	{
5657
		return $this->getViewState('Method','post');
5658
	}
5659
	public function setMethod($value)
5660
	{
5661
		$this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
5662
	}
5663
	public function getEnctype()
5664
	{
5665
		return $this->getViewState('Enctype','');
5666
	}
5667
	public function setEnctype($value)
5668
	{
5669
		$this->setViewState('Enctype',$value,'');
5670
	}
5671
	public function getName()
5672
	{
5673
		return $this->getUniqueID();
5674
	}
5675
}
5676
class TClientScriptManager extends TApplicationComponent
5677
{
5678
	const SCRIPT_PATH='Web/Javascripts/source';
5679
	const SCRIPT_LOADER='Web/Javascripts/clientscripts.php';
5680
	private $_page;
5681
	private $_hiddenFields=array();
5682
	private $_beginScripts=array();
5683
	private $_endScripts=array();
5684
	private $_scriptFiles=array();
5685
	private $_headScriptFiles=array();
5686
	private $_headScripts=array();
5687
	private $_styleSheetFiles=array();
5688
	private $_styleSheets=array();
5689
	private $_registeredPradoScripts=array();
5690
	private static $_pradoScripts;
5691
	public function __construct(TPage $owner)
5692
	{
5693
		$this->_page=$owner;
5694
	}
5695
	public function getRequiresHead()
5696
	{
5697
		return count($this->_styleSheetFiles) || count($this->_styleSheets)
5698
			|| count($this->_headScriptFiles) || count($this->_headScripts);
5699
	}
5700
	public function registerPradoScript($name)
5701
	{
5702
		$this->registerPradoScriptInternal($name);
5703
		$params=func_get_args();
5704
		$this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
5705
	}
5706
	private function registerPradoScriptInternal($name)
5707
	{
5708
		if(!isset($this->_registeredPradoScripts[$name]))
5709
		{
5710
			if(self::$_pradoScripts === null)
5711
			{
5712
				$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH.'/packages.php';
5713
				list($packages,$deps)= include($packageFile);
5714
				self::$_pradoScripts = $deps;
5715
			}
5716
			if(isset(self::$_pradoScripts[$name]))
5717
				$this->_registeredPradoScripts[$name]=true;
5718
			else
5719
				throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
5720
		}
5721
	}
5722
	public function getPradoScriptAssetUrl()
5723
	{
5724
		$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
5725
		$assets = Prado::getApplication()->getAssetManager();
5726
		return $assets->getPublishedUrl($base);
5727
	}
5728
	protected function renderPradoScripts($writer)
5729
	{
5730
		if(($packages=array_keys($this->_registeredPradoScripts))!==array())
5731
		{
5732
			$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
5733
			$url = $this->registerJavascriptPackages($base, $packages);
5734
			$writer->write(TJavaScript::renderScriptFile($url));
5735
		}
5736
	}
5737
	public function registerJavascriptPackages($base, $packages, $debug=null, $gzip=true)
5738
	{
5739
		list($path,$url) = $this->getPackagePathUrl($base);
5740
		$scriptLoaderPath = $path.'/'.basename(self::SCRIPT_LOADER);
5741
		$scriptLoaderSrc = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_LOADER;
5742
		if(!is_file($scriptLoaderPath))
5743
		{
5744
			copy($scriptLoaderSrc, $scriptLoaderPath);
5745
			chmod($scriptLoaderPath, PRADO_CHMOD);
5746
		}
5747
		$url .= '/'.basename(self::SCRIPT_LOADER).'?js='.implode(',', $packages);
5748
		if($debug!==false && $this->getApplication()->getMode()===TApplicationMode::Debug)
5749
		{
5750
			$this->verifyJavascriptPackages($base,$path,$packages);
5751
			$url.='&amp;mode=debug';
5752
		}
5753
		if($gzip===false)
5754
			$url.='&amp;gzip=false';
5755
		return $url;
5756
	}
5757
	protected function verifyJavascriptPackages($base,$path,$scripts)
5758
	{
5759
		$file = $path.'/packages.php';
5760
		if(is_file($file))
5761
		{
5762
			list($packs,$deps) = include($file);
5763
			if(count($missing = array_diff($scripts, array_keys($deps))) > 0)
5764
			{
5765
				throw new TConfigurationException('csmanager_invalid_packages',
5766
					$base.'/packages.php',implode(', ', $missing), implode(', ', array_keys($deps)));
5767
			}
5768
		}
5769
	}
5770
	protected function getPackagePathUrl($base)
5771
	{
5772
		$assets = Prado::getApplication()->getAssetManager();
5773
		if(strpos($base, $assets->getBaseUrl())===false)
5774
		{
5775
			if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
5776
				$base = $dir;
5777
			}
5778
			return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
5779
		}
5780
		else
5781
		{
5782
			return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
5783
		}
5784
	}
5785
	public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
5786
	{
5787
		$options = !is_array($options) ? array() : $options;
5788
		$class = new TReflectionClass($callbackHandler);
5789
		$clientSide = $callbackHandler->getActiveControl()->getClientSide();
5790
		$options = array_merge($options, $clientSide->getOptions()->toArray());
5791
		$optionString = TJavaScript::encode($options);
5792
		$this->registerPradoScriptInternal('ajax');
5793
		$id = $callbackHandler->getUniqueID();
5794
		return "new Prado.CallbackRequest('{$id}',{$optionString})";
5795
	}
5796
	public function registerCallbackControl($class, $options)
5797
	{
5798
		$optionString=TJavaScript::encode($options);
5799
		$code="new {$class}({$optionString});";
5800
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
5801
		$this->registerPradoScriptInternal('ajax');
5802
		$params=func_get_args();
5803
		$this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
5804
	}
5805
	public function registerPostBackControl($class,$options)
5806
	{
5807
		if($class === null) {
5808
			return;
5809
		}
5810
		if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
5811
			$options['FormID']=$form->getClientID();
5812
		$optionString=TJavaScript::encode($options);
5813
		$code="new {$class}({$optionString});";
5814
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
5815
		$this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]='';
5816
		$this->_hiddenFields[TPage::FIELD_POSTBACK_PARAMETER]='';
5817
		$this->registerPradoScriptInternal('prado');
5818
		$params=func_get_args();
5819
		$this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
5820
	}
5821
	public function registerDefaultButton($panel, $button)
5822
	{
5823
		$panelID=is_string($panel)?$panel:$panel->getUniqueID();
5824
		if(is_string($button))
5825
			$buttonID=$button;
5826
		else
5827
		{
5828
			$button->setIsDefaultButton(true);
5829
			$buttonID=$button->getUniqueID();
5830
		}
5831
		$options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
5832
		$code = "new Prado.WebUI.DefaultButton($options);";
5833
		$this->_endScripts['prado:'.$panelID]=$code;
5834
		$this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]='';
5835
		$this->registerPradoScriptInternal('prado');
5836
		$params=array($panelID,$buttonID);
5837
		$this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
5838
	}
5839
	protected function getDefaultButtonOptions($panelID, $buttonID)
5840
	{
5841
		$options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
5842
		$options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
5843
		$options['EventTarget'] = $buttonID;
5844
		$options['Event'] = 'click';
5845
		return $options;
5846
	}
5847
	public function registerFocusControl($target)
5848
	{
5849
		$this->registerPradoScriptInternal('effects');
5850
		if($target instanceof TControl)
5851
			$target=$target->getClientID();
5852
		$id = TJavaScript::quoteString($target);
5853
		$this->_endScripts['prado:focus'] = 'new Effect.ScrollTo("'.$id.'"); Prado.Element.focus("'.$id.'");';
5854
		$params=func_get_args();
5855
		$this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
5856
	}
5857
	public function registerStyleSheetFile($key,$url,$media='')
5858
	{
5859
		if($media==='')
5860
			$this->_styleSheetFiles[$key]=$url;
5861
		else
5862
			$this->_styleSheetFiles[$key]=array($url,$media);
5863
		$params=func_get_args();
5864
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
5865
	}
5866
	public function registerStyleSheet($key,$css,$media='')
5867
	{
5868
		$this->_styleSheets[$key]=$css;
5869
		$params=func_get_args();
5870
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
5871
	}
5872
	public function registerHeadScriptFile($key,$url)
5873
	{
5874
		$this->_headScriptFiles[$key]=$url;
5875
		$params=func_get_args();
5876
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
5877
	}
5878
	public function registerHeadScript($key,$script)
5879
	{
5880
		$this->_headScripts[$key]=$script;
5881
		$params=func_get_args();
5882
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
5883
	}
5884
	public function registerScriptFile($key,$url)
5885
	{
5886
		$this->_scriptFiles[$key]=$url;
5887
		$params=func_get_args();
5888
		$this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
5889
	}
5890
	public function registerBeginScript($key,$script)
5891
	{
5892
		$this->_beginScripts[$key]=$script;
5893
		$params=func_get_args();
5894
		$this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
5895
	}
5896
	public function registerEndScript($key,$script)
5897
	{
5898
		$this->_endScripts[$key]=$script;
5899
		$params=func_get_args();
5900
		$this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
5901
	}
5902
	public function registerHiddenField($name,$value)
5903
	{
5904
		$this->_hiddenFields[$name]=$value;
5905
		$params=func_get_args();
5906
		$this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
5907
	}
5908
	public function isStyleSheetFileRegistered($key)
5909
	{
5910
		return isset($this->_styleSheetFiles[$key]);
5911
	}
5912
	public function isStyleSheetRegistered($key)
5913
	{
5914
		return isset($this->_styleSheets[$key]);
5915
	}
5916
	public function isHeadScriptFileRegistered($key)
5917
	{
5918
		return isset($this->_headScriptFiles[$key]);
5919
	}
5920
	public function isHeadScriptRegistered($key)
5921
	{
5922
		return isset($this->_headScripts[$key]);
5923
	}
5924
	public function isScriptFileRegistered($key)
5925
	{
5926
		return isset($this->_scriptFiles[$key]);
5927
	}
5928
	public function isBeginScriptRegistered($key)
5929
	{
5930
		return isset($this->_beginScripts[$key]);
5931
	}
5932
	public function isEndScriptRegistered($key)
5933
	{
5934
		return isset($this->_endScripts[$key]);
5935
	}
5936
	public function hasEndScripts()
5937
	{
5938
		return count($this->_endScripts) > 0;
5939
	}
5940
	public function hasBeginScripts()
5941
	{
5942
		return count($this->_beginScripts) > 0;
5943
	}
5944
	public function isHiddenFieldRegistered($key)
5945
	{
5946
		return isset($this->_hiddenFields[$key]);
5947
	}
5948
	public function renderStyleSheetFiles($writer)
5949
	{
5950
		$str='';
5951
		foreach($this->_styleSheetFiles as $url)
5952
		{
5953
			if(is_array($url))
5954
				$str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
5955
			else
5956
				$str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
5957
		}
5958
		$writer->write($str);
5959
	}
5960
	public function renderStyleSheets($writer)
5961
	{
5962
		if(count($this->_styleSheets))
5963
			$writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
5964
	}
5965
	public function renderHeadScriptFiles($writer)
5966
	{
5967
		$writer->write(TJavaScript::renderScriptFiles($this->_headScriptFiles));
5968
	}
5969
	public function renderHeadScripts($writer)
5970
	{
5971
		$writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
5972
	}
5973
	public function renderScriptFiles($writer)
5974
	{
5975
		$this->renderPradoScripts($writer);
5976
		if(!empty($this->_scriptFiles))
5977
			$writer->write(TJavaScript::renderScriptFiles($this->_scriptFiles));
5978
	}
5979
	public function renderBeginScripts($writer)
5980
	{
5981
		$writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
5982
	}
5983
	public function renderEndScripts($writer)
5984
	{
5985
		$writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
5986
	}
5987
	public function renderHiddenFields($writer)
5988
	{
5989
		$str='';
5990
		foreach($this->_hiddenFields as $name=>$value)
5991
		{
5992
			$id=strtr($name,':','_');
5993
			if(is_array($value))
5994
			{
5995
				foreach($value as $v)
5996
					$str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
5997
			}
5998
			else
5999
			{
6000
				$str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
6001
			}
6002
		}
6003
		if($str!=='')
6004
			$writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
6005
	}
6006
}
6007
abstract class TClientSideOptions extends TComponent
6008
{
6009
	private $_options;
6010
	public function __construct()
6011
	{
6012
		$this->_options = Prado::createComponent('System.Collections.TMap');
6013
	}
6014
	protected function setFunction($name, $code)
6015
	{
6016
		if(!TJavaScript::isFunction($code))
6017
			$code = TJavaScript::quoteFunction($this->ensureFunction($code));
6018
		$this->setOption($name, $code);
6019
	}
6020
	protected function getOption($name)
6021
	{
6022
		return $this->_options->itemAt($name);
6023
	}
6024
	protected function setOption($name, $value)
6025
	{
6026
		$this->_options->add($name, $value);
6027
	}
6028
	public function getOptions()
6029
	{
6030
		return $this->_options;
6031
	}
6032
	protected function ensureFunction($javascript)
6033
	{
6034
		return "function(sender, parameter){ {$javascript} }";
6035
	}
6036
}
6037
class TPage extends TTemplateControl
6038
{
6039
	const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
6040
	const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
6041
	const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
6042
	const FIELD_PAGESTATE='PRADO_PAGESTATE';
6043
	const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
6044
	const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
6045
	private static $_systemPostFields=array(
6046
		'PRADO_POSTBACK_TARGET'=>true,
6047
		'PRADO_POSTBACK_PARAMETER'=>true,
6048
		'PRADO_LASTFOCUS'=>true,
6049
		'PRADO_PAGESTATE'=>true,
6050
		'PRADO_CALLBACK_TARGET'=>true,
6051
		'PRADO_CALLBACK_PARAMETER'=>true
6052
	);
6053
	private $_form;
6054
	private $_head;
6055
	private $_validators=array();
6056
	private $_validated=false;
6057
	private $_theme;
6058
	private $_title;
6059
	private $_styleSheet;
6060
	private $_clientScript;
6061
	private $_postData;
6062
	private $_restPostData;
6063
	private $_controlsPostDataChanged=array();
6064
	private $_controlsRequiringPostData=array();
6065
	private $_controlsRegisteredForPostData=array();
6066
	private $_postBackEventTarget;
6067
	private $_postBackEventParameter;
6068
	private $_formRendered=false;
6069
	private $_inFormRender=false;
6070
	private $_focus;
6071
	private $_pagePath='';
6072
	private $_enableStateValidation=true;
6073
	private $_enableStateEncryption=false;
6074
	private $_statePersisterClass='System.Web.UI.TPageStatePersister';
6075
	private $_statePersister;
6076
	private $_cachingStack;
6077
	private $_clientState='';
6078
	private $_postDataLoaders=array();
6079
	private $_isLoadingPostData=false;
6080
	private $_enableJavaScript=true;
6081
	public function __construct()
6082
	{
6083
		parent::__construct();
6084
		$this->setPage($this);
6085
	}
6086
	public function run($writer)
6087
	{
6088
		$this->determinePostBackMode();
6089
		if($this->getIsPostBack())
6090
		{
6091
			if($this->getIsCallback())
6092
				$this->processCallbackRequest($writer);
6093
			else
6094
				$this->processPostBackRequest($writer);
6095
		}
6096
		else
6097
			$this->processNormalRequest($writer);
6098
	}
6099
	protected function processNormalRequest($writer)
6100
	{
6101
		$this->onPreInit(null);
6102
		$this->initRecursive();
6103
		$this->onInitComplete(null);
6104
		$this->onPreLoad(null);
6105
		$this->loadRecursive();
6106
		$this->onLoadComplete(null);
6107
		$this->preRenderRecursive();
6108
		$this->onPreRenderComplete(null);
6109
		$this->savePageState();
6110
		$this->onSaveStateComplete(null);
6111
		$this->renderControl($writer);
6112
		$this->unloadRecursive();
6113
	}
6114
	protected function processPostBackRequest($writer)
6115
	{
6116
		$this->onPreInit(null);
6117
		$this->initRecursive();
6118
		$this->onInitComplete(null);
6119
		$this->_restPostData=new TMap;
6120
		$this->loadPageState();
6121
		$this->processPostData($this->_postData,true);
6122
		$this->onPreLoad(null);
6123
		$this->loadRecursive();
6124
		$this->processPostData($this->_restPostData,false);
6125
		$this->raiseChangedEvents();
6126
		$this->raisePostBackEvent();
6127
		$this->onLoadComplete(null);
6128
		$this->preRenderRecursive();
6129
		$this->onPreRenderComplete(null);
6130
		$this->savePageState();
6131
		$this->onSaveStateComplete(null);
6132
		$this->renderControl($writer);
6133
		$this->unloadRecursive();
6134
	}
6135
	protected function processCallbackRequest($writer)
6136
	{
6137
		Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
6138
		$this->setAdapter(new TActivePageAdapter($this));
6139
        if (($g=$this->getApplication()->getGlobalization(false))!==null &&
6140
            strtoupper($enc=$g->getCharset())!='UTF-8')
6141
                foreach ($this->_postData as $k=>$v)
6142
                    $this->_postData[$k]=iconv('UTF-8',$enc.'//IGNORE',$v);
6143
		$this->onPreInit(null);
6144
		$this->initRecursive();
6145
		$this->onInitComplete(null);
6146
		$this->_restPostData=new TMap;
6147
		$this->loadPageState();
6148
		$this->processPostData($this->_postData,true);
6149
		$this->onPreLoad(null);
6150
		$this->loadRecursive();
6151
		$this->processPostData($this->_restPostData,false);
6152
		$this->raiseChangedEvents();
6153
		$this->getAdapter()->processCallbackEvent($writer);
6154
		$this->onLoadComplete(null);
6155
		$this->preRenderRecursive();
6156
		$this->onPreRenderComplete(null);
6157
		$this->savePageState();
6158
		$this->onSaveStateComplete(null);
6159
		$this->getAdapter()->renderCallbackResponse($writer);
6160
		$this->unloadRecursive();
6161
	}
6162
	public function getCallbackClient()
6163
	{
6164
		if($this->getAdapter() !== null)
6165
			return $this->getAdapter()->getCallbackClientHandler();
6166
		else
6167
			return new TCallbackClientScript();
6168
	}
6169
	public function setCallbackClient($client)
6170
	{
6171
		$this->getAdapter()->setCallbackClientHandler($client);
6172
	}
6173
	public function getCallbackEventTarget()
6174
	{
6175
		return $this->getAdapter()->getCallbackEventTarget();
6176
	}
6177
	public function setCallbackEventTarget(TControl $control)
6178
	{
6179
		$this->getAdapter()->setCallbackEventTarget($control);
6180
	}
6181
	public function getCallbackEventParameter()
6182
	{
6183
		return $this->getAdapter()->getCallbackEventParameter();
6184
	}
6185
	public function setCallbackEventParameter($value)
6186
	{
6187
		$this->getAdapter()->setCallbackEventParameter($value);
6188
	}
6189
	public function registerPostDataLoader($control)
6190
	{
6191
		$id=is_string($control)?$control:$control->getUniqueID();
6192
		$this->_postDataLoaders[$id] = true;
6193
	}
6194
	public function getPostDataLoaders()
6195
	{
6196
		return array_keys($this->_postDataLoaders);
6197
	}
6198
	public function getForm()
6199
	{
6200
		return $this->_form;
6201
	}
6202
	public function setForm(TForm $form)
6203
	{
6204
		if($this->_form===null)
6205
			$this->_form=$form;
6206
		else
6207
			throw new TInvalidOperationException('page_form_duplicated');
6208
	}
6209
	public function getValidators($validationGroup=null)
6210
	{
6211
		if(!$this->_validators)
6212
			$this->_validators=new TList;
6213
		if($validationGroup===null)
6214
			return $this->_validators;
6215
		else
6216
		{
6217
			$list=new TList;
6218
			foreach($this->_validators as $validator)
6219
				if($validator->getValidationGroup()===$validationGroup)
6220
					$list->add($validator);
6221
			return $list;
6222
		}
6223
	}
6224
	public function validate($validationGroup=null)
6225
	{
6226
		$this->_validated=true;
6227
		if($this->_validators && $this->_validators->getCount())
6228
		{
6229
			if($validationGroup===null)
6230
			{
6231
				foreach($this->_validators as $validator)
6232
					$validator->validate();
6233
			}
6234
			else
6235
			{
6236
				foreach($this->_validators as $validator)
6237
				{
6238
					if($validator->getValidationGroup()===$validationGroup)
6239
						$validator->validate();
6240
				}
6241
			}
6242
		}
6243
	}
6244
	public function getIsValid()
6245
	{
6246
		if($this->_validated)
6247
		{
6248
			if($this->_validators && $this->_validators->getCount())
6249
			{
6250
				foreach($this->_validators as $validator)
6251
					if(!$validator->getIsValid())
6252
						return false;
6253
			}
6254
			return true;
6255
		}
6256
		else
6257
			throw new TInvalidOperationException('page_isvalid_unknown');
6258
	}
6259
	public function getTheme()
6260
	{
6261
		if(is_string($this->_theme))
6262
			$this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
6263
		return $this->_theme;
6264
	}
6265
	public function setTheme($value)
6266
	{
6267
		$this->_theme=empty($value)?null:$value;
6268
	}
6269
	public function getStyleSheetTheme()
6270
	{
6271
		if(is_string($this->_styleSheet))
6272
			$this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
6273
		return $this->_styleSheet;
6274
	}
6275
	public function setStyleSheetTheme($value)
6276
	{
6277
		$this->_styleSheet=empty($value)?null:$value;
6278
	}
6279
	public function applyControlSkin($control)
6280
	{
6281
		if(($theme=$this->getTheme())!==null)
6282
			$theme->applySkin($control);
6283
	}
6284
	public function applyControlStyleSheet($control)
6285
	{
6286
		if(($theme=$this->getStyleSheetTheme())!==null)
6287
			$theme->applySkin($control);
6288
	}
6289
	public function getClientScript()
6290
	{
6291
		if(!$this->_clientScript)
6292
			$this->_clientScript=new TClientScriptManager($this);
6293
		return $this->_clientScript;
6294
	}
6295
	public function onPreInit($param)
6296
	{
6297
		$this->raiseEvent('OnPreInit',$this,$param);
6298
	}
6299
	public function onInitComplete($param)
6300
	{
6301
		$this->raiseEvent('OnInitComplete',$this,$param);
6302
	}
6303
	public function onPreLoad($param)
6304
	{
6305
		$this->raiseEvent('OnPreLoad',$this,$param);
6306
	}
6307
	public function onLoadComplete($param)
6308
	{
6309
		$this->raiseEvent('OnLoadComplete',$this,$param);
6310
	}
6311
	public function onPreRenderComplete($param)
6312
	{
6313
		$this->raiseEvent('OnPreRenderComplete',$this,$param);
6314
		$cs=$this->getClientScript();
6315
		$theme=$this->getTheme();
6316
		if($theme instanceof ITheme)
6317
		{
6318
			foreach($theme->getStyleSheetFiles() as $url)
6319
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
6320
			foreach($theme->getJavaScriptFiles() as $url)
6321
				$cs->registerHeadScriptFile($url,$url);
6322
		}
6323
		$styleSheet=$this->getStyleSheetTheme();
6324
		if($styleSheet instanceof ITheme)
6325
		{
6326
			foreach($styleSheet->getStyleSheetFiles() as $url)
6327
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
6328
			foreach($styleSheet->getJavaScriptFiles() as $url)
6329
				$cs->registerHeadScriptFile($url,$url);
6330
		}
6331
		if($cs->getRequiresHead() && $this->getHead()===null)
6332
			throw new TConfigurationException('page_head_required');
6333
	}
6334
	private function getCssMediaType($url)
6335
	{
6336
		$segs=explode('.',basename($url));
6337
		if(isset($segs[2]))
6338
			return $segs[count($segs)-2];
6339
		else
6340
			return '';
6341
	}
6342
	public function onSaveStateComplete($param)
6343
	{
6344
		$this->raiseEvent('OnSaveStateComplete',$this,$param);
6345
	}
6346
	private function determinePostBackMode()
6347
	{
6348
		$postData=$this->getRequest();
6349
		if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
6350
			$this->_postData=$postData;
6351
	}
6352
	public function getIsPostBack()
6353
	{
6354
		return $this->_postData!==null;
6355
	}
6356
	public function getIsCallback()
6357
	{
6358
		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
6359
	}
6360
	public function saveState()
6361
	{
6362
		parent::saveState();
6363
		$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
6364
	}
6365
	public function loadState()
6366
	{
6367
		parent::loadState();
6368
		$this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
6369
	}
6370
	protected function loadPageState()
6371
	{
6372
		$state=$this->getStatePersister()->load();
6373
		$this->loadStateRecursive($state,$this->getEnableViewState());
6374
	}
6375
	protected function savePageState()
6376
	{
6377
		$state=&$this->saveStateRecursive($this->getEnableViewState());
6378
		$this->getStatePersister()->save($state);
6379
	}
6380
	protected function isSystemPostField($field)
6381
	{
6382
		return isset(self::$_systemPostFields[$field]);
6383
	}
6384
	public function registerRequiresPostData($control)
6385
	{
6386
		$id=is_string($control)?$control:$control->getUniqueID();
6387
		$this->_controlsRegisteredForPostData[$id]=true;
6388
		$this->registerPostDataLoader($id);
6389
		$params=func_get_args();
6390
		foreach($this->getCachingStack() as $item)
6391
			$item->registerAction('Page','registerRequiresPostData',$id);
6392
	}
6393
	public function getPostBackEventTarget()
6394
	{
6395
		if($this->_postBackEventTarget===null && $this->_postData!==null)
6396
		{
6397
			$eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
6398
			if(!empty($eventTarget))
6399
				$this->_postBackEventTarget=$this->findControl($eventTarget);
6400
		}
6401
		return $this->_postBackEventTarget;
6402
	}
6403
	public function setPostBackEventTarget(TControl $control)
6404
	{
6405
		$this->_postBackEventTarget=$control;
6406
	}
6407
	public function getPostBackEventParameter()
6408
	{
6409
		if($this->_postBackEventParameter===null && $this->_postData!==null)
6410
		{
6411
			if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
6412
				$this->_postBackEventParameter='';
6413
		}
6414
		return $this->_postBackEventParameter;
6415
	}
6416
	public function setPostBackEventParameter($value)
6417
	{
6418
		$this->_postBackEventParameter=$value;
6419
	}
6420
	protected function processPostData($postData,$beforeLoad)
6421
	{
6422
		$this->_isLoadingPostData=true;
6423
		if($beforeLoad)
6424
			$this->_restPostData=new TMap;
6425
		foreach($postData as $key=>$value)
6426
		{
6427
			if($this->isSystemPostField($key))
6428
				continue;
6429
			else if($control=$this->findControl($key))
6430
			{
6431
				if($control instanceof IPostBackDataHandler)
6432
				{
6433
					if($control->loadPostData($key,$postData))
6434
						$this->_controlsPostDataChanged[]=$control;
6435
				}
6436
				else if($control instanceof IPostBackEventHandler &&
6437
					empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
6438
				{
6439
					$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);
6440
				}
6441
				unset($this->_controlsRequiringPostData[$key]);
6442
			}
6443
			else if($beforeLoad)
6444
				$this->_restPostData->add($key,$value);
6445
		}
6446
		foreach($this->_controlsRequiringPostData as $key=>$value)
6447
		{
6448
			if($control=$this->findControl($key))
6449
			{
6450
				if($control instanceof IPostBackDataHandler)
6451
				{
6452
					if($control->loadPostData($key,$this->_postData))
6453
						$this->_controlsPostDataChanged[]=$control;
6454
				}
6455
				else
6456
					throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
6457
				unset($this->_controlsRequiringPostData[$key]);
6458
			}
6459
		}
6460
		$this->_isLoadingPostData=false;
6461
	}
6462
	public function getIsLoadingPostData()
6463
	{
6464
		return $this->_isLoadingPostData;
6465
	}
6466
	private function raiseChangedEvents()
6467
	{
6468
		foreach($this->_controlsPostDataChanged as $control)
6469
			$control->raisePostDataChangedEvent();
6470
	}
6471
	private function raisePostBackEvent()
6472
	{
6473
		if(($postBackHandler=$this->getPostBackEventTarget())===null)
6474
			$this->validate();
6475
		else if($postBackHandler instanceof IPostBackEventHandler)
6476
			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
6477
	}
6478
	public function ensureRenderInForm($control)
6479
	{
6480
		if(!$this->getIsCallback() && !$this->_inFormRender)
6481
			throw new TConfigurationException('page_control_outofform',get_class($control),$control->getUniqueID());
6482
	}
6483
	public function beginFormRender($writer)
6484
	{
6485
		if($this->_formRendered)
6486
			throw new TConfigurationException('page_form_duplicated');
6487
		$this->_formRendered=true;
6488
		$this->_inFormRender=true;
6489
		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
6490
	}
6491
	public function endFormRender($writer)
6492
	{
6493
		if($this->_focus)
6494
		{
6495
			if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
6496
				$focus=$this->_focus->getClientID();
6497
			else
6498
				$focus=$this->_focus;
6499
			$this->getClientScript()->registerFocusControl($focus);
6500
		}
6501
		else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
6502
			$this->getClientScript()->registerFocusControl($lastFocus);
6503
		$this->_inFormRender=false;
6504
	}
6505
	public function setFocus($value)
6506
	{
6507
		$this->_focus=$value;
6508
	}
6509
	public function getClientSupportsJavaScript()
6510
	{
6511
		return $this->_enableJavaScript;
6512
	}
6513
	public function setClientSupportsJavaScript($value)
6514
	{
6515
		$this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
6516
	}
6517
	public function getHead()
6518
	{
6519
		return $this->_head;
6520
	}
6521
	public function setHead(THead $value)
6522
	{
6523
		if($this->_head)
6524
			throw new TInvalidOperationException('page_head_duplicated');
6525
		$this->_head=$value;
6526
		if($this->_title!==null)
6527
		{
6528
			$this->_head->setTitle($this->_title);
6529
			$this->_title=null;
6530
		}
6531
	}
6532
	public function getTitle()
6533
	{
6534
		if($this->_head)
6535
			return $this->_head->getTitle();
6536
		else
6537
			return $this->_title===null ? '' : $this->_title;
6538
	}
6539
	public function setTitle($value)
6540
	{
6541
		if($this->_head)
6542
			$this->_head->setTitle($value);
6543
		else
6544
			$this->_title=$value;
6545
	}
6546
	public function getClientState()
6547
	{
6548
		return $this->_clientState;
6549
	}
6550
	public function setClientState($state)
6551
	{
6552
		$this->_clientState=$state;
6553
	}
6554
	public function getRequestClientState()
6555
	{
6556
		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
6557
	}
6558
	public function getStatePersisterClass()
6559
	{
6560
		return $this->_statePersisterClass;
6561
	}
6562
	public function setStatePersisterClass($value)
6563
	{
6564
		$this->_statePersisterClass=$value;
6565
	}
6566
	public function getStatePersister()
6567
	{
6568
		if($this->_statePersister===null)
6569
		{
6570
			$this->_statePersister=Prado::createComponent($this->_statePersisterClass);
6571
			if(!($this->_statePersister instanceof IPageStatePersister))
6572
				throw new TInvalidDataTypeException('page_statepersister_invalid');
6573
			$this->_statePersister->setPage($this);
6574
		}
6575
		return $this->_statePersister;
6576
	}
6577
	public function getEnableStateValidation()
6578
	{
6579
		return $this->_enableStateValidation;
6580
	}
6581
	public function setEnableStateValidation($value)
6582
	{
6583
		$this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
6584
	}
6585
	public function getEnableStateEncryption()
6586
	{
6587
		return $this->_enableStateEncryption;
6588
	}
6589
	public function setEnableStateEncryption($value)
6590
	{
6591
		$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
6592
	}
6593
	public function getPagePath()
6594
	{
6595
		return $this->_pagePath;
6596
	}
6597
	public function setPagePath($value)
6598
	{
6599
		$this->_pagePath=$value;
6600
	}
6601
	public function registerCachingAction($context,$funcName,$funcParams)
6602
	{
6603
		if($this->_cachingStack)
6604
		{
6605
			foreach($this->_cachingStack as $cache)
6606
				$cache->registerAction($context,$funcName,$funcParams);
6607
		}
6608
	}
6609
	public function getCachingStack()
6610
	{
6611
		if(!$this->_cachingStack)
6612
			$this->_cachingStack=new TStack;
6613
		return $this->_cachingStack;
6614
	}
6615
}
6616
interface IPageStatePersister
6617
{
6618
	public function getPage();
6619
	public function setPage(TPage $page);
6620
	public function save($state);
6621
	public function load();
6622
}
6623
class TPageStateFormatter
6624
{
6625
	public static function serialize($page,$data)
6626
	{
6627
		$sm=$page->getApplication()->getSecurityManager();
6628
		if($page->getEnableStateValidation())
6629
			$str=$sm->hashData(Prado::serialize($data));
6630
		else
6631
			$str=Prado::serialize($data);
6632
		if(extension_loaded('zlib'))
6633
			$str=gzcompress($str);
6634
		if($page->getEnableStateEncryption())
6635
			$str=$sm->encrypt($str);
6636
		return base64_encode($str);
6637
	}
6638
	public static function unserialize($page,$data)
6639
	{
6640
		$str=base64_decode($data);
6641
		if($str==='')
6642
			return null;
6643
		if($str!==false)
6644
		{
6645
			$sm=$page->getApplication()->getSecurityManager();
6646
			if($page->getEnableStateEncryption())
6647
				$str=$sm->decrypt($str);
6648
			if(extension_loaded('zlib'))
6649
				$str=@gzuncompress($str);
6650
			if($page->getEnableStateValidation())
6651
			{
6652
				if(($str=$sm->validateData($str))!==false)
6653
					return Prado::unserialize($str);
6654
			}
6655
			else
6656
				return $str;
6657
		}
6658
		return null;
6659
	}
6660
}
6661
class TOutputCache extends TControl implements INamingContainer
6662
{
6663
	const CACHE_ID_PREFIX='prado:outputcache';
6664
	private $_cacheModuleID='';
6665
	private $_dataCached=false;
6666
	private $_cacheAvailable=false;
6667
	private $_cacheChecked=false;
6668
	private $_cacheKey=null;
6669
	private $_duration=60;
6670
	private $_cache=null;
6671
	private $_contents;
6672
	private $_state;
6673
	private $_actions=array();
6674
	private $_varyByParam='';
6675
	private $_keyPrefix='';
6676
	private $_varyBySession=false;
6677
	private $_cachePostBack=false;
6678
	private $_cacheTime=0;
6679
	public function getAllowChildControls()
6680
	{
6681
		$this->determineCacheability();
6682
		return !$this->_dataCached;
6683
	}
6684
	private function determineCacheability()
6685
	{
6686
		if(!$this->_cacheChecked)
6687
		{
6688
			$this->_cacheChecked=true;
6689
			if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
6690
			{
6691
				if($this->_cacheModuleID!=='')
6692
				{
6693
					$this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
6694
					if(!($this->_cache instanceof ICache))
6695
						throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
6696
				}
6697
				else
6698
					$this->_cache=$this->getApplication()->getCache();
6699
				if($this->_cache!==null)
6700
				{
6701
					$this->_cacheAvailable=true;
6702
					$data=$this->_cache->get($this->getCacheKey());
6703
					if(is_array($data))
6704
					{
6705
						$param=new TOutputCacheCheckDependencyEventParameter;
6706
						$param->setCacheTime(isset($data[3])?$data[3]:0);
6707
						$this->onCheckDependency($param);
6708
						$this->_dataCached=$param->getIsValid();
6709
					}
6710
					else
6711
						$this->_dataCached=false;
6712
					if($this->_dataCached)
6713
						list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
6714
				}
6715
			}
6716
		}
6717
	}
6718
	protected function initRecursive($namingContainer=null)
6719
	{
6720
		if($this->_cacheAvailable && !$this->_dataCached)
6721
		{
6722
			$stack=$this->getPage()->getCachingStack();
6723
			$stack->push($this);
6724
			parent::initRecursive($namingContainer);
6725
			$stack->pop();
6726
		}
6727
		else
6728
			parent::initRecursive($namingContainer);
6729
	}
6730
	protected function loadRecursive()
6731
	{
6732
		if($this->_cacheAvailable && !$this->_dataCached)
6733
		{
6734
			$stack=$this->getPage()->getCachingStack();
6735
			$stack->push($this);
6736
			parent::loadRecursive();
6737
			$stack->pop();
6738
		}
6739
		else
6740
		{
6741
			if($this->_dataCached)
6742
				$this->performActions();
6743
			parent::loadRecursive();
6744
		}
6745
	}
6746
	private function performActions()
6747
	{
6748
		$page=$this->getPage();
6749
		$cs=$page->getClientScript();
6750
		foreach($this->_actions as $action)
6751
		{
6752
			if($action[0]==='Page.ClientScript')
6753
				call_user_func_array(array($cs,$action[1]),$action[2]);
6754
			else if($action[0]==='Page')
6755
				call_user_func_array(array($page,$action[1]),$action[2]);
6756
			else
6757
				call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
6758
		}
6759
	}
6760
	protected function preRenderRecursive()
6761
	{
6762
		if($this->_cacheAvailable && !$this->_dataCached)
6763
		{
6764
			$stack=$this->getPage()->getCachingStack();
6765
			$stack->push($this);
6766
			parent::preRenderRecursive();
6767
			$stack->pop();
6768
		}
6769
		else
6770
			parent::preRenderRecursive();
6771
	}
6772
	protected function loadStateRecursive(&$state,$needViewState=true)
6773
	{
6774
		$st=unserialize($state);
6775
		parent::loadStateRecursive($st,$needViewState);
6776
	}
6777
	protected function &saveStateRecursive($needViewState=true)
6778
	{
6779
		if($this->_dataCached)
6780
			return $this->_state;
6781
		else
6782
		{
6783
			$st=parent::saveStateRecursive($needViewState);
6784
			$this->_state=serialize($st);
6785
			return $this->_state;
6786
		}
6787
	}
6788
	public function registerAction($context,$funcName,$funcParams)
6789
	{
6790
		$this->_actions[]=array($context,$funcName,$funcParams);
6791
	}
6792
	private function getCacheKey()
6793
	{
6794
		if($this->_cacheKey===null)
6795
			$this->_cacheKey=$this->calculateCacheKey();
6796
		return $this->_cacheKey;
6797
	}
6798
	protected function calculateCacheKey()
6799
	{
6800
		$key=$this->getBaseCacheKey();
6801
		if($this->_varyBySession)
6802
			$key.=$this->getSession()->getSessionID();
6803
		if($this->_varyByParam!=='')
6804
		{
6805
			$params=array();
6806
			$request=$this->getRequest();
6807
			foreach(explode(',',$this->_varyByParam) as $name)
6808
			{
6809
				$name=trim($name);
6810
				$params[$name]=$request->itemAt($name);
6811
			}
6812
			$key.=serialize($params);
6813
		}
6814
		$param=new TOutputCacheCalculateKeyEventParameter;
6815
		$this->onCalculateKey($param);
6816
		$key.=$param->getCacheKey();
6817
		return $key;
6818
	}
6819
	protected function getBaseCacheKey()
6820
	{
6821
		return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
6822
	}
6823
	public function getCacheModuleID()
6824
	{
6825
		return $this->_cacheModuleID;
6826
	}
6827
	public function setCacheModuleID($value)
6828
	{
6829
		$this->_cacheModuleID=$value;
6830
	}
6831
	public function setCacheKeyPrefix($value)
6832
	{
6833
		$this->_keyPrefix=$value;
6834
	}
6835
	public function getCacheTime()
6836
	{
6837
		return $this->_cacheTime;
6838
	}
6839
	protected function getCacheDependency()
6840
	{
6841
		return null;
6842
	}
6843
	public function getContentCached()
6844
	{
6845
		return $this->_dataCached;
6846
	}
6847
	public function getDuration()
6848
	{
6849
		return $this->_duration;
6850
	}
6851
	public function setDuration($value)
6852
	{
6853
		if(($value=TPropertyValue::ensureInteger($value))<0)
6854
			throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
6855
		$this->_duration=$value;
6856
	}
6857
	public function getVaryByParam()
6858
	{
6859
		return $this->_varyByParam;
6860
	}
6861
	public function setVaryByParam($value)
6862
	{
6863
		$this->_varyByParam=trim($value);
6864
	}
6865
	public function getVaryBySession()
6866
	{
6867
		return $this->_varyBySession;
6868
	}
6869
	public function setVaryBySession($value)
6870
	{
6871
		$this->_varyBySession=TPropertyValue::ensureBoolean($value);
6872
	}
6873
	public function getCachingPostBack()
6874
	{
6875
		return $this->_cachePostBack;
6876
	}
6877
	public function setCachingPostBack($value)
6878
	{
6879
		$this->_cachePostBack=TPropertyValue::ensureBoolean($value);
6880
	}
6881
	public function onCheckDependency($param)
6882
	{
6883
		$this->raiseEvent('OnCheckDependency',$this,$param);
6884
	}
6885
	public function onCalculateKey($param)
6886
	{
6887
		$this->raiseEvent('OnCalculateKey',$this,$param);
6888
	}
6889
	public function render($writer)
6890
	{
6891
		if($this->_dataCached)
6892
			$writer->write($this->_contents);
6893
		else if($this->_cacheAvailable)
6894
		{
6895
			$textWriter=new TTextWriter;
6896
			$stack=$this->getPage()->getCachingStack();
6897
			$stack->push($this);
6898
			parent::render(new THtmlWriter($textWriter));
6899
			$stack->pop();
6900
			$content=$textWriter->flush();
6901
			$data=array($content,$this->_state,$this->_actions,time());
6902
			$this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
6903
			$writer->write($content);
6904
		}
6905
		else
6906
			parent::render($writer);
6907
	}
6908
}
6909
class TOutputCacheCheckDependencyEventParameter extends TEventParameter
6910
{
6911
	private $_isValid=true;
6912
	private $_cacheTime=0;
6913
	public function getIsValid()
6914
	{
6915
		return $this->_isValid;
6916
	}
6917
	public function setIsValid($value)
6918
	{
6919
		$this->_isValid=TPropertyValue::ensureBoolean($value);
6920
	}
6921
	public function getCacheTime()
6922
	{
6923
		return $this->_cacheTime;
6924
	}
6925
	public function setCacheTime($value)
6926
	{
6927
		$this->_cacheTime=TPropertyValue::ensureInteger($value);
6928
	}
6929
}
6930
class TOutputCacheCalculateKeyEventParameter extends TEventParameter
6931
{
6932
	private $_cacheKey='';
6933
	public function getCacheKey()
6934
	{
6935
		return $this->_cacheKey;
6936
	}
6937
	public function setCacheKey($value)
6938
	{
6939
		$this->_cacheKey=TPropertyValue::ensureString($value);
6940
	}
6941
}
6942
class TTemplateManager extends TModule
6943
{
6944
	const TEMPLATE_FILE_EXT='.tpl';
6945
	const TEMPLATE_CACHE_PREFIX='prado:template:';
6946
	public function init($config)
6947
	{
6948
		$this->getService()->setTemplateManager($this);
6949
	}
6950
	public function getTemplateByClassName($className)
6951
	{
6952
		$class=new ReflectionClass($className);
6953
		$tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
6954
		return $this->getTemplateByFileName($tplFile);
6955
	}
6956
	public function getTemplateByFileName($fileName)
6957
	{
6958
		if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
6959
		{
6960
			if(($cache=$this->getApplication()->getCache())===null)
6961
				return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
6962
			else
6963
			{
6964
				$array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
6965
				if(is_array($array))
6966
				{
6967
					list($template,$timestamps)=$array;
6968
					if($this->getApplication()->getMode()===TApplicationMode::Performance)
6969
						return $template;
6970
					$cacheValid=true;
6971
					foreach($timestamps as $tplFile=>$timestamp)
6972
					{
6973
						if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
6974
						{
6975
							$cacheValid=false;
6976
							break;
6977
						}
6978
					}
6979
					if($cacheValid)
6980
						return $template;
6981
				}
6982
				$template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
6983
				$includedFiles=$template->getIncludedFiles();
6984
				$timestamps=array();
6985
				$timestamps[$fileName]=filemtime($fileName);
6986
				foreach($includedFiles as $includedFile)
6987
					$timestamps[$includedFile]=filemtime($includedFile);
6988
				$cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
6989
				return $template;
6990
			}
6991
		}
6992
		else
6993
			return null;
6994
	}
6995
	protected function getLocalizedTemplate($filename)
6996
	{
6997
		if(($app=$this->getApplication()->getGlobalization(false))===null)
6998
			return is_file($filename)?$filename:null;
6999
		foreach($app->getLocalizedResource($filename) as $file)
7000
		{
7001
			if(($file=realpath($file))!==false && is_file($file))
7002
				return $file;
7003
		}
7004
		return null;
7005
	}
7006
}
7007
class TTemplate extends TApplicationComponent implements ITemplate
7008
{
7009
	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';
7010
	const CONFIG_DATABIND=0;
7011
	const CONFIG_EXPRESSION=1;
7012
	const CONFIG_ASSET=2;
7013
	const CONFIG_PARAMETER=3;
7014
	const CONFIG_LOCALIZATION=4;
7015
	const CONFIG_TEMPLATE=5;
7016
	private $_tpl=array();
7017
	private $_directive=array();
7018
	private $_contextPath;
7019
	private $_tplFile=null;
7020
	private $_startingLine=0;
7021
	private $_content;
7022
	private $_sourceTemplate=true;
7023
	private $_hashCode='';
7024
	private $_tplControl=null;
7025
	private $_includedFiles=array();
7026
	private $_includeAtLine=array();
7027
	private $_includeLines=array();
7028
	public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
7029
	{
7030
		$this->_sourceTemplate=$sourceTemplate;
7031
		$this->_contextPath=$contextPath;
7032
		$this->_tplFile=$tplFile;
7033
		$this->_startingLine=$startingLine;
7034
		$this->_content=$template;
7035
		$this->_hashCode=md5($template);
7036
		$this->parse($template);
7037
		$this->_content=null;
7038
	}
7039
	public function getTemplateFile()
7040
	{
7041
		return $this->_tplFile;
7042
	}
7043
	public function getIsSourceTemplate()
7044
	{
7045
		return $this->_sourceTemplate;
7046
	}
7047
	public function getContextPath()
7048
	{
7049
		return $this->_contextPath;
7050
	}
7051
	public function getDirective()
7052
	{
7053
		return $this->_directive;
7054
	}
7055
	public function getHashCode()
7056
	{
7057
		return $this->_hashCode;
7058
	}
7059
	public function &getItems()
7060
	{
7061
		return $this->_tpl;
7062
	}
7063
	public function instantiateIn($tplControl,$parentControl=null)
7064
	{
7065
		$this->_tplControl=$tplControl;
7066
		if($parentControl===null)
7067
			$parentControl=$tplControl;
7068
		if(($page=$tplControl->getPage())===null)
7069
			$page=$this->getService()->getRequestedPage();
7070
		$controls=array();
7071
		$directChildren=array();
7072
		foreach($this->_tpl as $key=>$object)
7073
		{
7074
			if($object[0]===-1)
7075
				$parent=$parentControl;
7076
			else if(isset($controls[$object[0]]))
7077
				$parent=$controls[$object[0]];
7078
			else
7079
				continue;
7080
			if(isset($object[2]))
7081
			{
7082
				$component=Prado::createComponent($object[1]);
7083
				$properties=&$object[2];
7084
				if($component instanceof TControl)
7085
				{
7086
					if($component instanceof TOutputCache)
7087
						$component->setCacheKeyPrefix($this->_hashCode.$key);
7088
					$component->setTemplateControl($tplControl);
7089
					if(isset($properties['id']))
7090
					{
7091
						if(is_array($properties['id']))
7092
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
7093
						$tplControl->registerObject($properties['id'],$component);
7094
					}
7095
					if(isset($properties['skinid']))
7096
					{
7097
						if(is_array($properties['skinid']))
7098
							$component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
7099
						else
7100
							$component->setSkinID($properties['skinid']);
7101
						unset($properties['skinid']);
7102
					}
7103
					$component->trackViewState(false);
7104
					$component->applyStyleSheetSkin($page);
7105
					foreach($properties as $name=>$value)
7106
						$this->configureControl($component,$name,$value);
7107
					$component->trackViewState(true);
7108
					if($parent===$parentControl)
7109
						$directChildren[]=$component;
7110
					else
7111
						$component->createdOnTemplate($parent);
7112
					if($component->getAllowChildControls())
7113
						$controls[$key]=$component;
7114
				}
7115
				else if($component instanceof TComponent)
7116
				{
7117
					$controls[$key]=$component;
7118
					if(isset($properties['id']))
7119
					{
7120
						if(is_array($properties['id']))
7121
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
7122
						$tplControl->registerObject($properties['id'],$component);
7123
						if(!$component->hasProperty('id'))
7124
							unset($properties['id']);
7125
					}
7126
					foreach($properties as $name=>$value)
7127
						$this->configureComponent($component,$name,$value);
7128
					if($parent===$parentControl)
7129
						$directChildren[]=$component;
7130
					else
7131
						$component->createdOnTemplate($parent);
7132
				}
7133
			}
7134
			else
7135
			{
7136
				if($object[1] instanceof TCompositeLiteral)
7137
				{
7138
					$o=clone $object[1];
7139
					$o->setContainer($tplControl);
7140
					if($parent===$parentControl)
7141
						$directChildren[]=$o;
7142
					else
7143
						$parent->addParsedObject($o);
7144
				}
7145
				else
7146
				{
7147
					if($parent===$parentControl)
7148
						$directChildren[]=$object[1];
7149
					else
7150
						$parent->addParsedObject($object[1]);
7151
				}
7152
			}
7153
		}
7154
		foreach($directChildren as $control)
7155
		{
7156
			if($control instanceof TComponent)
7157
				$control->createdOnTemplate($parentControl);
7158
			else
7159
				$parentControl->addParsedObject($control);
7160
		}
7161
	}
7162
	protected function configureControl($control,$name,$value)
7163
	{
7164
		if(strncasecmp($name,'on',2)===0)
7165
			$this->configureEvent($control,$name,$value,$control);
7166
		else if(($pos=strrpos($name,'.'))===false)
7167
			$this->configureProperty($control,$name,$value);
7168
		else
7169
			$this->configureSubProperty($control,$name,$value);
7170
	}
7171
	protected function configureComponent($component,$name,$value)
7172
	{
7173
		if(strpos($name,'.')===false)
7174
			$this->configureProperty($component,$name,$value);
7175
		else
7176
			$this->configureSubProperty($component,$name,$value);
7177
	}
7178
	protected function configureEvent($control,$name,$value,$contextControl)
7179
	{
7180
		if(strpos($value,'.')===false)
7181
			$control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
7182
		else
7183
			$control->attachEventHandler($name,array($contextControl,$value));
7184
	}
7185
	protected function configureProperty($component,$name,$value)
7186
	{
7187
		if(is_array($value))
7188
		{
7189
			switch($value[0])
7190
			{
7191
				case self::CONFIG_DATABIND:
7192
					$component->bindProperty($name,$value[1]);
7193
					break;
7194
				case self::CONFIG_EXPRESSION:
7195
					if($component instanceof TControl)
7196
						$component->autoBindProperty($name,$value[1]);
7197
					else
7198
					{
7199
						$setter='set'.$name;
7200
						$component->$setter($this->_tplControl->evaluateExpression($value[1]));
7201
					}
7202
					break;
7203
				case self::CONFIG_TEMPLATE:
7204
					$setter='set'.$name;
7205
					$component->$setter($value[1]);
7206
					break;
7207
				case self::CONFIG_ASSET:
7208
					$setter='set'.$name;
7209
					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
7210
					$component->$setter($url);
7211
					break;
7212
				case self::CONFIG_PARAMETER:
7213
					$setter='set'.$name;
7214
					$component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
7215
					break;
7216
				case self::CONFIG_LOCALIZATION:
7217
					$setter='set'.$name;
7218
					$component->$setter(Prado::localize($value[1]));
7219
					break;
7220
				default:
7221
					throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
7222
					break;
7223
			}
7224
		}
7225
		else
7226
		{
7227
			$setter='set'.$name;
7228
			$component->$setter($value);
7229
		}
7230
	}
7231
	protected function configureSubProperty($component,$name,$value)
7232
	{
7233
		if(is_array($value))
7234
		{
7235
			switch($value[0])
7236
			{
7237
				case self::CONFIG_DATABIND:
7238
					$component->bindProperty($name,$value[1]);
7239
					break;
7240
				case self::CONFIG_EXPRESSION:
7241
					if($component instanceof TControl)
7242
						$component->autoBindProperty($name,$value[1]);
7243
					else
7244
						$component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
7245
					break;
7246
				case self::CONFIG_TEMPLATE:
7247
					$component->setSubProperty($name,$value[1]);
7248
					break;
7249
				case self::CONFIG_ASSET:
7250
					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
7251
					$component->setSubProperty($name,$url);
7252
					break;
7253
				case self::CONFIG_PARAMETER:
7254
					$component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
7255
					break;
7256
				case self::CONFIG_LOCALIZATION:
7257
					$component->setSubProperty($name,Prado::localize($value[1]));
7258
					break;
7259
				default:
7260
					throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
7261
					break;
7262
			}
7263
		}
7264
		else
7265
			$component->setSubProperty($name,$value);
7266
	}
7267
	protected function parse($input)
7268
	{
7269
		$input=$this->preprocess($input);
7270
		$tpl=&$this->_tpl;
7271
		$n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
7272
		$expectPropEnd=false;
7273
		$textStart=0;
7274
        $stack=array();
7275
		$container=-1;
7276
		$matchEnd=0;
7277
		$c=0;
7278
		$this->_directive=null;
7279
		try
7280
		{
7281
			for($i=0;$i<$n;++$i)
7282
			{
7283
				$match=&$matches[$i];
7284
				$str=$match[0][0];
7285
				$matchStart=$match[0][1];
7286
				$matchEnd=$matchStart+strlen($str)-1;
7287
				if(strpos($str,'<com:')===0)
7288
				{
7289
					if($expectPropEnd)
7290
						continue;
7291
					if($matchStart>$textStart)
7292
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
7293
					$textStart=$matchEnd+1;
7294
					$type=$match[1][0];
7295
					$attributes=$this->parseAttributes($match[2][0],$match[2][1]);
7296
					$this->validateAttributes($type,$attributes);
7297
					$tpl[$c++]=array($container,$type,$attributes);
7298
					if($str[strlen($str)-2]!=='/')
7299
					{
7300
						array_push($stack,$type);
7301
						$container=$c-1;
7302
					}
7303
				}
7304
				else if(strpos($str,'</com:')===0)
7305
				{
7306
					if($expectPropEnd)
7307
						continue;
7308
					if($matchStart>$textStart)
7309
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
7310
					$textStart=$matchEnd+1;
7311
					$type=$match[1][0];
7312
					if(empty($stack))
7313
						throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
7314
					$name=array_pop($stack);
7315
					if($name!==$type)
7316
					{
7317
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
7318
						throw new TConfigurationException('template_closingtag_expected',$tag);
7319
					}
7320
					$container=$tpl[$container][0];
7321
				}
7322
				else if(strpos($str,'<%@')===0)
7323
				{
7324
					if($expectPropEnd)
7325
						continue;
7326
					if($matchStart>$textStart)
7327
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
7328
					$textStart=$matchEnd+1;
7329
					if(isset($tpl[0]) || $this->_directive!==null)
7330
						throw new TConfigurationException('template_directive_nonunique');
7331
					$this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
7332
				}
7333
				else if(strpos($str,'<%')===0)
7334
				{
7335
					if($expectPropEnd)
7336
						continue;
7337
					if($matchStart>$textStart)
7338
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
7339
					$textStart=$matchEnd+1;
7340
					$literal=trim($match[5][0]);
7341
					if($str[2]==='=')
7342
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
7343
					else if($str[2]==='%')
7344
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
7345
					else if($str[2]==='#')
7346
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
7347
					else if($str[2]==='$')
7348
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
7349
					else if($str[2]==='~')
7350
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
7351
					else if($str[2]==='/')
7352
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'"));
7353
					else if($str[2]==='[')
7354
					{
7355
						$literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
7356
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
7357
					}
7358
				}
7359
				else if(strpos($str,'<prop:')===0)
7360
				{
7361
					if(strrpos($str,'/>')===strlen($str)-2)
7362
					{
7363
						if($expectPropEnd)
7364
							continue;
7365
						if($matchStart>$textStart)
7366
							$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
7367
						$textStart=$matchEnd+1;
7368
						$prop=strtolower($match[6][0]);
7369
						$attrs=$this->parseAttributes($match[7][0],$match[7][1]);
7370
						$attributes=array();
7371
						foreach($attrs as $name=>$value)
7372
							$attributes[$prop.'.'.$name]=$value;
7373
						$type=$tpl[$container][1];
7374
						$this->validateAttributes($type,$attributes);
7375
						foreach($attributes as $name=>$value)
7376
						{
7377
							if(isset($tpl[$container][2][$name]))
7378
								throw new TConfigurationException('template_property_duplicated',$name);
7379
							$tpl[$container][2][$name]=$value;
7380
						}
7381
					}
7382
					else
7383
					{
7384
						$prop=strtolower($match[3][0]);
7385
						array_push($stack,'@'.$prop);
7386
						if(!$expectPropEnd)
7387
						{
7388
							if($matchStart>$textStart)
7389
								$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
7390
							$textStart=$matchEnd+1;
7391
							$expectPropEnd=true;
7392
						}
7393
					}
7394
				}
7395
				else if(strpos($str,'</prop:')===0)
7396
				{
7397
					$prop=strtolower($match[3][0]);
7398
					if(empty($stack))
7399
						throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
7400
					$name=array_pop($stack);
7401
					if($name!=='@'.$prop)
7402
					{
7403
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
7404
						throw new TConfigurationException('template_closingtag_expected',$tag);
7405
					}
7406
					if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
7407
					{
7408
						if($matchStart>$textStart)
7409
						{
7410
							$value=substr($input,$textStart,$matchStart-$textStart);
7411
							if(substr($prop,-8,8)==='template')
7412
								$value=$this->parseTemplateProperty($value,$textStart);
7413
							else
7414
								$value=$this->parseAttribute($value);
7415
							if($container>=0)
7416
							{
7417
								$type=$tpl[$container][1];
7418
								$this->validateAttributes($type,array($prop=>$value));
7419
								if(isset($tpl[$container][2][$prop]))
7420
									throw new TConfigurationException('template_property_duplicated',$prop);
7421
								$tpl[$container][2][$prop]=$value;
7422
							}
7423
							else
7424
								$this->_directive[$prop]=$value;
7425
							$textStart=$matchEnd+1;
7426
						}
7427
						$expectPropEnd=false;
7428
					}
7429
				}
7430
				else if(strpos($str,'<!--')===0)
7431
				{
7432
					if($expectPropEnd)
7433
						throw new TConfigurationException('template_comments_forbidden');
7434
					if($matchStart>$textStart)
7435
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
7436
					$textStart=$matchEnd+1;
7437
				}
7438
				else
7439
					throw new TConfigurationException('template_matching_unexpected',$match);
7440
			}
7441
			if(!empty($stack))
7442
			{
7443
				$name=array_pop($stack);
7444
				$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
7445
				throw new TConfigurationException('template_closingtag_expected',$tag);
7446
			}
7447
			if($textStart<strlen($input))
7448
				$tpl[$c++]=array($container,substr($input,$textStart));
7449
		}
7450
		catch(Exception $e)
7451
		{
7452
			if(($e instanceof TException) && ($e instanceof TTemplateException))
7453
				throw $e;
7454
			if($matchEnd===0)
7455
				$line=$this->_startingLine+1;
7456
			else
7457
				$line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
7458
			$this->handleException($e,$line,$input);
7459
		}
7460
		if($this->_directive===null)
7461
			$this->_directive=array();
7462
		$objects=array();
7463
		$parent=null;
7464
		$merged=array();
7465
		foreach($tpl as $id=>$object)
7466
		{
7467
			if(isset($object[2]) || $object[0]!==$parent)
7468
			{
7469
				if($parent!==null)
7470
				{
7471
					if(count($merged[1])===1 && is_string($merged[1][0]))
7472
						$objects[$id-1]=array($merged[0],$merged[1][0]);
7473
					else
7474
						$objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
7475
				}
7476
				if(isset($object[2]))
7477
				{
7478
					$parent=null;
7479
					$objects[$id]=$object;
7480
				}
7481
				else
7482
				{
7483
					$parent=$object[0];
7484
					$merged=array($parent,array($object[1]));
7485
				}
7486
			}
7487
			else
7488
				$merged[1][]=$object[1];
7489
		}
7490
		if($parent!==null)
7491
		{
7492
			if(count($merged[1])===1 && is_string($merged[1][0]))
7493
				$objects[$id]=array($merged[0],$merged[1][0]);
7494
			else
7495
				$objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
7496
		}
7497
		$tpl=$objects;
7498
		return $objects;
7499
	}
7500
	protected function parseAttributes($str,$offset)
7501
	{
7502
		if($str==='')
7503
			return array();
7504
		$pattern='/([\w\.]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
7505
		$attributes=array();
7506
		$n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
7507
		for($i=0;$i<$n;++$i)
7508
		{
7509
			$match=&$matches[$i];
7510
			$name=strtolower($match[1][0]);
7511
			if(isset($attributes[$name]))
7512
				throw new TConfigurationException('template_property_duplicated',$name);
7513
			$value=$match[2][0];
7514
			if(substr($name,-8,8)==='template')
7515
			{
7516
				if($value[0]==='\'' || $value[0]==='"')
7517
					$attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
7518
				else
7519
					$attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
7520
			}
7521
			else
7522
			{
7523
				if($value[0]==='\'' || $value[0]==='"')
7524
					$attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
7525
				else
7526
					$attributes[$name]=$this->parseAttribute($value);
7527
			}
7528
		}
7529
		return $attributes;
7530
	}
7531
	protected function parseTemplateProperty($content,$offset)
7532
	{
7533
		$line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
7534
		return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
7535
	}
7536
	protected function parseAttribute($value)
7537
	{
7538
		if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
7539
		{
7540
			$isDataBind=false;
7541
			$textStart=0;
7542
			$expr='';
7543
			for($i=0;$i<$n;++$i)
7544
			{
7545
				$match=$matches[0][$i];
7546
				$token=$match[0];
7547
				$offset=$match[1];
7548
				$length=strlen($token);
7549
				if($token[2]==='#')
7550
					$isDataBind=true;
7551
				if($offset>$textStart)
7552
					$expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
7553
				$expr.='.('.substr($token,3,$length-5).')';
7554
				$textStart=$offset+$length;
7555
			}
7556
			$length=strlen($value);
7557
			if($length>$textStart)
7558
				$expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
7559
			if($isDataBind)
7560
				return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
7561
			else
7562
				return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
7563
		}
7564
		else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
7565
		{
7566
			$value=$matches[1];
7567
			if($value[2]==='~')
7568
				return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
7569
			else if($value[2]==='[')
7570
				return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
7571
			else if($value[2]==='$')
7572
				return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
7573
		}
7574
		else
7575
			return $value;
7576
	}
7577
	protected function validateAttributes($type,$attributes)
7578
	{
7579
		Prado::using($type);
7580
		if(($pos=strrpos($type,'.'))!==false)
7581
			$className=substr($type,$pos+1);
7582
		else
7583
			$className=$type;
7584
		$class=new TReflectionClass($className);
7585
		if(is_subclass_of($className,'TControl') || $className==='TControl')
7586
		{
7587
			foreach($attributes as $name=>$att)
7588
			{
7589
				if(($pos=strpos($name,'.'))!==false)
7590
				{
7591
					$subname=substr($name,0,$pos);
7592
					if(!$class->hasMethod('get'.$subname))
7593
						throw new TConfigurationException('template_property_unknown',$type,$subname);
7594
				}
7595
				else if(strncasecmp($name,'on',2)===0)
7596
				{
7597
					if(!$class->hasMethod($name))
7598
						throw new TConfigurationException('template_event_unknown',$type,$name);
7599
					else if(!is_string($att))
7600
						throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
7601
				}
7602
				else
7603
				{
7604
					if(!$class->hasMethod('set'.$name))
7605
					{
7606
						if($class->hasMethod('get'.$name))
7607
							throw new TConfigurationException('template_property_readonly',$type,$name);
7608
						else
7609
							throw new TConfigurationException('template_property_unknown',$type,$name);
7610
					}
7611
					else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
7612
					{
7613
						if(strcasecmp($name,'id')===0)
7614
							throw new TConfigurationException('template_controlid_invalid',$type);
7615
						else if(strcasecmp($name,'skinid')===0)
7616
							throw new TConfigurationException('template_controlskinid_invalid',$type);
7617
					}
7618
				}
7619
			}
7620
		}
7621
		else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
7622
		{
7623
			foreach($attributes as $name=>$att)
7624
			{
7625
				if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
7626
					throw new TConfigurationException('template_databind_forbidden',$type,$name);
7627
				if(($pos=strpos($name,'.'))!==false)
7628
				{
7629
					$subname=substr($name,0,$pos);
7630
					if(!$class->hasMethod('get'.$subname))
7631
						throw new TConfigurationException('template_property_unknown',$type,$subname);
7632
				}
7633
				else if(strncasecmp($name,'on',2)===0)
7634
					throw new TConfigurationException('template_event_forbidden',$type,$name);
7635
				else
7636
				{
7637
					if(strcasecmp($name,'id')!==0 && !$class->hasMethod('set'.$name))
7638
					{
7639
						if($class->hasMethod('get'.$name))
7640
							throw new TConfigurationException('template_property_readonly',$type,$name);
7641
						else
7642
							throw new TConfigurationException('template_property_unknown',$type,$name);
7643
					}
7644
				}
7645
			}
7646
		}
7647
		else
7648
			throw new TConfigurationException('template_component_required',$type);
7649
	}
7650
	public function getIncludedFiles()
7651
	{
7652
		return $this->_includedFiles;
7653
	}
7654
	protected function handleException($e,$line,$input=null)
7655
	{
7656
		$srcFile=$this->_tplFile;
7657
		if(($n=count($this->_includedFiles))>0)
7658
		{
7659
			for($i=$n-1;$i>=0;--$i)
7660
			{
7661
				if($this->_includeAtLine[$i]<=$line)
7662
				{
7663
					if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
7664
					{
7665
						$line=$line-$this->_includeAtLine[$i]+1;
7666
						$srcFile=$this->_includedFiles[$i];
7667
						break;
7668
					}
7669
					else
7670
						$line=$line-$this->_includeLines[$i]+1;
7671
				}
7672
			}
7673
		}
7674
		$exception=new TTemplateException('template_format_invalid',$e->getMessage());
7675
		$exception->setLineNumber($line);
7676
		if(!empty($srcFile))
7677
			$exception->setTemplateFile($srcFile);
7678
		else
7679
			$exception->setTemplateSource($input);
7680
		throw $exception;
7681
	}
7682
	protected function preprocess($input)
7683
	{
7684
		if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
7685
		{
7686
			for($i=0;$i<$n;++$i)
7687
			{
7688
				$filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
7689
				if($filePath!==null && is_file($filePath))
7690
					$this->_includedFiles[]=$filePath;
7691
				else
7692
				{
7693
					$errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
7694
					$this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
7695
				}
7696
			}
7697
			$base=0;
7698
			for($i=0;$i<$n;++$i)
7699
			{
7700
				$ext=file_get_contents($this->_includedFiles[$i]);
7701
				$length=strlen($matches[$i][0][0]);
7702
				$offset=$base+$matches[$i][0][1];
7703
				$this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
7704
				$this->_includeLines[$i]=count(explode("\n",$ext));
7705
				$input=substr_replace($input,$ext,$offset,$length);
7706
				$base+=strlen($ext)-$length;
7707
			}
7708
		}
7709
		return $input;
7710
	}
7711
}
7712
class TThemeManager extends TModule
7713
{
7714
	const DEFAULT_BASEPATH='themes';
7715
	private $_initialized=false;
7716
	private $_basePath=null;
7717
	private $_baseUrl=null;
7718
	public function init($config)
7719
	{
7720
		$this->_initialized=true;
7721
		$service=$this->getService();
7722
		if($service instanceof TPageService)
7723
			$service->setThemeManager($this);
7724
		else
7725
			throw new TConfigurationException('thememanager_service_unavailable');
7726
	}
7727
	public function getTheme($name)
7728
	{
7729
		$themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
7730
		$themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
7731
		return new TTheme($themePath,$themeUrl);
7732
	}
7733
	public function getAvailableThemes()
7734
	{
7735
		$themes=array();
7736
		$basePath=$this->getBasePath();
7737
		$folder=@opendir($basePath);
7738
		while($file=@readdir($folder))
7739
		{
7740
			if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
7741
				$themes[]=$file;
7742
		}
7743
		closedir($folder);
7744
		return $themes;
7745
	}
7746
	public function getBasePath()
7747
	{
7748
		if($this->_basePath===null)
7749
		{
7750
			$this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
7751
			if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
7752
				throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
7753
			$this->_basePath=$basePath;
7754
		}
7755
		return $this->_basePath;
7756
	}
7757
	public function setBasePath($value)
7758
	{
7759
		if($this->_initialized)
7760
			throw new TInvalidOperationException('thememanager_basepath_unchangeable');
7761
		else
7762
		{
7763
			$this->_basePath=Prado::getPathOfNamespace($value);
7764
			if($this->_basePath===null || !is_dir($this->_basePath))
7765
				throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
7766
		}
7767
	}
7768
	public function getBaseUrl()
7769
	{
7770
		if($this->_baseUrl===null)
7771
		{
7772
			$appPath=dirname($this->getRequest()->getApplicationFilePath());
7773
			$basePath=$this->getBasePath();
7774
			if(strpos($basePath,$appPath)===false)
7775
				throw new TConfigurationException('thememanager_baseurl_required');
7776
			$appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
7777
			$this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
7778
		}
7779
		return $this->_baseUrl;
7780
	}
7781
	public function setBaseUrl($value)
7782
	{
7783
		$this->_baseUrl=rtrim($value,'/');
7784
	}
7785
}
7786
class TTheme extends TApplicationComponent implements ITheme
7787
{
7788
	const THEME_CACHE_PREFIX='prado:theme:';
7789
	const SKIN_FILE_EXT='.skin';
7790
	private $_themePath;
7791
	private $_themeUrl;
7792
	private $_skins=null;
7793
	private $_name='';
7794
	private $_cssFiles=array();
7795
	private $_jsFiles=array();
7796
	public function __construct($themePath,$themeUrl)
7797
	{
7798
		$this->_themeUrl=$themeUrl;
7799
		$this->_themePath=realpath($themePath);
7800
		$this->_name=basename($themePath);
7801
		$cacheValid=false;
7802
		if(($cache=$this->getApplication()->getCache())!==null)
7803
		{
7804
			$array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
7805
			if(is_array($array))
7806
			{
7807
				list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
7808
				if($this->getApplication()->getMode()!==TApplicationMode::Performance)
7809
				{
7810
					if(($dir=opendir($themePath))===false)
7811
						throw new TIOException('theme_path_inexistent',$themePath);
7812
					$cacheValid=true;
7813
					while(($file=readdir($dir))!==false)
7814
					{
7815
						if($file==='.' || $file==='..')
7816
							continue;
7817
						else if(basename($file,'.css')!==$file)
7818
							$this->_cssFiles[]=$themeUrl.'/'.$file;
7819
						else if(basename($file,'.js')!==$file)
7820
							$this->_jsFiles[]=$themeUrl.'/'.$file;
7821
						else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
7822
						{
7823
							$cacheValid=false;
7824
							break;
7825
						}
7826
					}
7827
					closedir($dir);
7828
					if($cacheValid)
7829
						$this->_skins=$skins;
7830
				}
7831
				else
7832
				{
7833
					$cacheValid=true;
7834
					$this->_cssFiles=$cssFiles;
7835
					$this->_jsFiles=$jsFiles;
7836
					$this->_skins=$skins;
7837
				}
7838
			}
7839
		}
7840
		if(!$cacheValid)
7841
		{
7842
			$this->_cssFiles=array();
7843
			$this->_jsFiles=array();
7844
			$this->_skins=array();
7845
			if(($dir=opendir($themePath))===false)
7846
				throw new TIOException('theme_path_inexistent',$themePath);
7847
			while(($file=readdir($dir))!==false)
7848
			{
7849
				if($file==='.' || $file==='..')
7850
					continue;
7851
				else if(basename($file,'.css')!==$file)
7852
					$this->_cssFiles[]=$themeUrl.'/'.$file;
7853
				else if(basename($file,'.js')!==$file)
7854
					$this->_jsFiles[]=$themeUrl.'/'.$file;
7855
				else if(basename($file,self::SKIN_FILE_EXT)!==$file)
7856
				{
7857
					$template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
7858
					foreach($template->getItems() as $skin)
7859
					{
7860
						if(!isset($skin[2]))
7861
							continue;
7862
						else if($skin[0]!==-1)
7863
							throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
7864
						$type=$skin[1];
7865
						$id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
7866
						unset($skin[2]['skinid']);
7867
						if(isset($this->_skins[$type][$id]))
7868
							throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
7869
						$this->_skins[$type][$id]=$skin[2];
7870
					}
7871
				}
7872
			}
7873
			closedir($dir);
7874
			sort($this->_cssFiles);
7875
			sort($this->_jsFiles);
7876
			if($cache!==null)
7877
				$cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
7878
		}
7879
	}
7880
	public function getName()
7881
	{
7882
		return $this->_name;
7883
	}
7884
	protected function setName($value)
7885
	{
7886
		$this->_name = $value;
7887
	}
7888
	public function getBaseUrl()
7889
	{
7890
		return $this->_themeUrl;
7891
	}
7892
	protected function setBaseUrl($value)
7893
	{
7894
		$this->_themeUrl=rtrim($value,'/');
7895
	}
7896
	public function getBasePath()
7897
	{
7898
		return $this->_themePath;
7899
	}
7900
	protected function setBasePath($value)
7901
	{
7902
		$this->_themePath=$value;
7903
	}
7904
	public function getSkins()
7905
	{
7906
		return $this->_skins;
7907
	}
7908
	protected function setSkins($value)
7909
	{
7910
		$this->_skins = $value;
7911
	}
7912
	public function applySkin($control)
7913
	{
7914
		$type=get_class($control);
7915
		if(($id=$control->getSkinID())==='')
7916
			$id=0;
7917
		if(isset($this->_skins[$type][$id]))
7918
		{
7919
			foreach($this->_skins[$type][$id] as $name=>$value)
7920
			{
7921
				if(is_array($value))
7922
				{
7923
					switch($value[0])
7924
					{
7925
						case TTemplate::CONFIG_EXPRESSION:
7926
							$value=$this->evaluateExpression($value[1]);
7927
							break;
7928
						case TTemplate::CONFIG_ASSET:
7929
							$value=$this->_themeUrl.'/'.ltrim($value[1],'/');
7930
							break;
7931
						case TTemplate::CONFIG_DATABIND:
7932
							$control->bindProperty($name,$value[1]);
7933
							break;
7934
						case TTemplate::CONFIG_PARAMETER:
7935
							$control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
7936
							break;
7937
						case TTemplate::CONFIG_TEMPLATE:
7938
							$control->setSubProperty($name,$value[1]);
7939
							break;
7940
						case TTemplate::CONFIG_LOCALIZATION:
7941
							$control->setSubProperty($name,Prado::localize($value[1]));
7942
							break;
7943
						default:
7944
							throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
7945
							break;
7946
					}
7947
				}
7948
				if(!is_array($value))
7949
				{
7950
					if(strpos($name,'.')===false)
7951
					{
7952
						if($control->hasProperty($name))
7953
						{
7954
							if($control->canSetProperty($name))
7955
							{
7956
								$setter='set'.$name;
7957
								$control->$setter($value);
7958
							}
7959
							else
7960
								throw new TConfigurationException('theme_property_readonly',$type,$name);
7961
						}
7962
						else
7963
							throw new TConfigurationException('theme_property_undefined',$type,$name);
7964
					}
7965
					else
7966
						$control->setSubProperty($name,$value);
7967
				}
7968
			}
7969
			return true;
7970
		}
7971
		else
7972
			return false;
7973
	}
7974
	public function getStyleSheetFiles()
7975
	{
7976
		return $this->_cssFiles;
7977
	}
7978
	protected function setStyleSheetFiles($value)
7979
	{
7980
		$this->_cssFiles=$value;
7981
	}
7982
	public function getJavaScriptFiles()
7983
	{
7984
		return $this->_jsFiles;
7985
	}
7986
	protected function setJavaScriptFiles($value)
7987
	{
7988
		$this->_jsFiles=$value;
7989
	}
7990
}
7991
class TPageService extends TService
7992
{
7993
	const CONFIG_FILE='config.xml';
7994
	const DEFAULT_BASEPATH='pages';
7995
	const CONFIG_CACHE_PREFIX='prado:pageservice:';
7996
	const PAGE_FILE_EXT='.page';
7997
	private $_basePath=null;
7998
	private $_basePageClass='TPage';
7999
	private $_defaultPage='Home';
8000
	private $_pagePath=null;
8001
	private $_page=null;
8002
	private $_properties=array();
8003
	private $_initialized=false;
8004
	private $_themeManager=null;
8005
	private $_templateManager=null;
8006
	public function init($config)
8007
	{
8008
		$pageConfig=$this->loadPageConfig($config);
8009
		$this->initPageContext($pageConfig);
8010
		$this->_initialized=true;
8011
	}
8012
	protected function initPageContext($pageConfig)
8013
	{
8014
		$application=$this->getApplication();
8015
		foreach($pageConfig->getApplicationConfigurations() as $appConfig)
8016
			$application->applyConfiguration($appConfig);
8017
		$this->applyConfiguration($pageConfig);
8018
	}
8019
	protected function applyConfiguration($config)
8020
	{
8021
		$this->_properties=array_merge($this->_properties, $config->getProperties());
8022
		$this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
8023
		$pagePath=$this->getRequestedPagePath();
8024
		foreach($config->getExternalConfigurations() as $filePath=>$params)
8025
		{
8026
			list($configPagePath,$condition)=$params;
8027
			if($condition!==true)
8028
				$condition=$this->evaluateExpression($condition);
8029
			if($condition)
8030
			{
8031
				if(($path=Prado::getPathOfNamespace($filePath,TApplication::CONFIG_FILE_EXT))===null || !is_file($path))
8032
					throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
8033
				$c=new TPageConfiguration($pagePath);
8034
				$c->loadFromFile($path,$configPagePath);
8035
				$this->applyConfiguration($c);
8036
			}
8037
		}
8038
	}
8039
	protected function determineRequestedPagePath()
8040
	{
8041
		$pagePath=$this->getRequest()->getServiceParameter();
8042
		if(empty($pagePath))
8043
			$pagePath=$this->getDefaultPage();
8044
		return $pagePath;
8045
	}
8046
	protected function loadPageConfig($config)
8047
	{
8048
		$application=$this->getApplication();
8049
		$pagePath=$this->getRequestedPagePath();
8050
		if(($cache=$application->getCache())===null)
8051
		{
8052
			$pageConfig=new TPageConfiguration($pagePath);
8053
			if($config!==null)
8054
				$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
8055
			$pageConfig->loadFromFiles($this->getBasePath());
8056
		}
8057
		else
8058
		{
8059
			$configCached=true;
8060
			$currentTimestamp=array();
8061
			$arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
8062
			if(is_array($arr))
8063
			{
8064
				list($pageConfig,$timestamps)=$arr;
8065
				if($application->getMode()!==TApplicationMode::Performance)
8066
				{
8067
					foreach($timestamps as $fileName=>$timestamp)
8068
					{
8069
						if($fileName===0)
8070
						{
8071
							$appConfigFile=$application->getConfigurationFile();
8072
							$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
8073
							if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
8074
								$configCached=false;
8075
						}
8076
						else
8077
						{
8078
							$currentTimestamp[$fileName]=@filemtime($fileName);
8079
							if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
8080
								$configCached=false;
8081
						}
8082
					}
8083
				}
8084
			}
8085
			else
8086
			{
8087
				$configCached=false;
8088
				$paths=explode('.',$pagePath);
8089
				$configPath=$this->getBasePath();
8090
				foreach($paths as $path)
8091
				{
8092
					$configFile=$configPath.DIRECTORY_SEPARATOR.self::CONFIG_FILE;
8093
					$currentTimestamp[$configFile]=@filemtime($configFile);
8094
					$configPath.=DIRECTORY_SEPARATOR.$path;
8095
				}
8096
				$appConfigFile=$application->getConfigurationFile();
8097
				$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
8098
			}
8099
			if(!$configCached)
8100
			{
8101
				$pageConfig=new TPageConfiguration($pagePath);
8102
				if($config!==null)
8103
					$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
8104
				$pageConfig->loadFromFiles($this->getBasePath());
8105
				$cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
8106
			}
8107
		}
8108
		return $pageConfig;
8109
	}
8110
	public function getTemplateManager()
8111
	{
8112
		if(!$this->_templateManager)
8113
		{
8114
			$this->_templateManager=new TTemplateManager;
8115
			$this->_templateManager->init(null);
8116
		}
8117
		return $this->_templateManager;
8118
	}
8119
	public function setTemplateManager(TTemplateManager $value)
8120
	{
8121
		$this->_templateManager=$value;
8122
	}
8123
	public function getThemeManager()
8124
	{
8125
		if(!$this->_themeManager)
8126
		{
8127
			$this->_themeManager=new TThemeManager;
8128
			$this->_themeManager->init(null);
8129
		}
8130
		return $this->_themeManager;
8131
	}
8132
	public function setThemeManager(TThemeManager $value)
8133
	{
8134
		$this->_themeManager=$value;
8135
	}
8136
	public function getRequestedPagePath()
8137
	{
8138
		if($this->_pagePath===null)
8139
		{
8140
			$this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
8141
			if(empty($this->_pagePath))
8142
				throw new THttpException(404,'pageservice_page_required');
8143
		}
8144
		return $this->_pagePath;
8145
	}
8146
	public function getRequestedPage()
8147
	{
8148
		return $this->_page;
8149
	}
8150
	public function getDefaultPage()
8151
	{
8152
		return $this->_defaultPage;
8153
	}
8154
	public function setDefaultPage($value)
8155
	{
8156
		if($this->_initialized)
8157
			throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
8158
		else
8159
			$this->_defaultPage=$value;
8160
	}
8161
	public function getDefaultPageUrl()
8162
	{
8163
		return $this->constructUrl($this->getDefaultPage());
8164
	}
8165
	public function getBasePath()
8166
	{
8167
		if($this->_basePath===null)
8168
		{
8169
			$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
8170
			if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
8171
				throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
8172
		}
8173
		return $this->_basePath;
8174
	}
8175
	public function setBasePath($value)
8176
	{
8177
		if($this->_initialized)
8178
			throw new TInvalidOperationException('pageservice_basepath_unchangeable');
8179
		else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
8180
			throw new TConfigurationException('pageservice_basepath_invalid',$value);
8181
		$this->_basePath=realpath($path);
8182
	}
8183
	public function setBasePageClass($value)
8184
	{
8185
		$this->_basePageClass=$value;
8186
	}
8187
	public function getBasePageClass()
8188
	{
8189
		return $this->_basePageClass;
8190
	}
8191
	public function run()
8192
	{
8193
		$this->_page=$this->createPage($this->getRequestedPagePath());
8194
		$this->runPage($this->_page,$this->_properties);
8195
	}
8196
	protected function createPage($pagePath)
8197
	{
8198
		$path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
8199
		$hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
8200
		$hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
8201
		if(!$hasTemplateFile && !$hasClassFile)
8202
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
8203
		if($hasClassFile)
8204
		{
8205
			$className=basename($path);
8206
			if(!class_exists($className,false))
8207
				include_once($path.Prado::CLASS_FILE_EXT);
8208
		}
8209
		else
8210
		{
8211
			$className=$this->getBasePageClass();
8212
			Prado::using($className);
8213
			if(($pos=strrpos($className,'.'))!==false)
8214
				$className=substr($className,$pos+1);
8215
		}
8216
 		if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
8217
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
8218
		$page=new $className;
8219
		$page->setPagePath($pagePath);
8220
		if($hasTemplateFile)
8221
			$page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
8222
		return $page;
8223
	}
8224
	protected function runPage($page,$properties)
8225
	{
8226
		foreach($properties as $name=>$value)
8227
			$page->setSubProperty($name,$value);
8228
		$page->run($this->getResponse()->createHtmlWriter());
8229
	}
8230
	public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
8231
	{
8232
		return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
8233
	}
8234
}
8235
class TPageConfiguration extends TComponent
8236
{
8237
	private $_appConfigs=array();
8238
	private $_properties=array();
8239
	private $_rules=array();
8240
	private $_includes=array();
8241
	private $_pagePath='';
8242
	public function __construct($pagePath)
8243
	{
8244
		$this->_pagePath=$pagePath;
8245
	}
8246
	public function getExternalConfigurations()
8247
	{
8248
		return $this->_includes;
8249
	}
8250
	public function getProperties()
8251
	{
8252
		return $this->_properties;
8253
	}
8254
	public function getRules()
8255
	{
8256
		return $this->_rules;
8257
	}
8258
	public function getApplicationConfigurations()
8259
	{
8260
		return $this->_appConfigs;
8261
	}
8262
	public function loadFromFiles($basePath)
8263
	{
8264
		$paths=explode('.',$this->_pagePath);
8265
		$page=array_pop($paths);
8266
		$path=$basePath;
8267
		$configPagePath='';
8268
		foreach($paths as $p)
8269
		{
8270
			$this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath);
8271
			$path.=DIRECTORY_SEPARATOR.$p;
8272
			if($configPagePath==='')
8273
				$configPagePath=$p;
8274
			else
8275
				$configPagePath.='.'.$p;
8276
		}
8277
		$this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath);
8278
		$this->_rules=new TAuthorizationRuleCollection($this->_rules);
8279
	}
8280
	public function loadFromFile($fname,$configPagePath)
8281
	{
8282
		if(empty($fname) || !is_file($fname))
8283
			return;
8284
		$dom=new TXmlDocument;
8285
		if($dom->loadFromFile($fname))
8286
			$this->loadFromXml($dom,dirname($fname),$configPagePath);
8287
		else
8288
			throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
8289
	}
8290
	public function loadFromXml($dom,$configPath,$configPagePath)
8291
	{
8292
		$this->loadApplicationConfigurationFromXml($dom,$configPath);
8293
		$this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
8294
	}
8295
	public function loadApplicationConfigurationFromXml($dom,$configPath)
8296
	{
8297
		$appConfig=new TApplicationConfiguration;
8298
		$appConfig->loadFromXml($dom,$configPath);
8299
		$this->_appConfigs[]=$appConfig;
8300
	}
8301
	public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
8302
	{
8303
		if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
8304
		{
8305
			$rules=array();
8306
			foreach($authorizationNode->getElements() as $node)
8307
			{
8308
				$patterns=$node->getAttribute('pages');
8309
				$ruleApplies=false;
8310
				if(empty($patterns) || trim($patterns)==='*')
8311
					$ruleApplies=true;
8312
				else
8313
				{
8314
					foreach(explode(',',$patterns) as $pattern)
8315
					{
8316
						if(($pattern=trim($pattern))!=='')
8317
						{
8318
							if($configPagePath!=='')
8319
								$pattern=$configPagePath.'.'.$pattern;
8320
							if(strcasecmp($pattern,$this->_pagePath)===0)
8321
							{
8322
								$ruleApplies=true;
8323
								break;
8324
							}
8325
							if($pattern[strlen($pattern)-1]==='*')
8326
							{
8327
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
8328
								{
8329
									$ruleApplies=true;
8330
									break;
8331
								}
8332
							}
8333
						}
8334
					}
8335
				}
8336
				if($ruleApplies)
8337
					$rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
8338
			}
8339
			$this->_rules=array_merge($rules,$this->_rules);
8340
		}
8341
		if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
8342
		{
8343
			$this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
8344
			foreach($pagesNode->getElementsByTagName('page') as $node)
8345
			{
8346
				$properties=$node->getAttributes();
8347
				$id=$properties->remove('id');
8348
				if(empty($id))
8349
					throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
8350
				$matching=false;
8351
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
8352
				if(strcasecmp($id,$this->_pagePath)===0)
8353
					$matching=true;
8354
				else if($id[strlen($id)-1]==='*')
8355
					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
8356
				if($matching)
8357
					$this->_properties=array_merge($this->_properties,$properties->toArray());
8358
			}
8359
		}
8360
		foreach($dom->getElementsByTagName('include') as $node)
8361
		{
8362
			if(($when=$node->getAttribute('when'))===null)
8363
				$when=true;
8364
			if(($filePath=$node->getAttribute('file'))===null)
8365
				throw new TConfigurationException('pageserviceconf_includefile_required');
8366
			if(isset($this->_includes[$filePath]))
8367
				$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
8368
			else
8369
				$this->_includes[$filePath]=array($configPagePath,$when);
8370
		}
8371
	}
8372
}
8373
class TAssetManager extends TModule
8374
{
8375
	const DEFAULT_BASEPATH='assets';
8376
	private $_basePath=null;
8377
	private $_baseUrl=null;
8378
	private $_checkTimestamp=false;
8379
	private $_application;
8380
	private $_published=array();
8381
	private $_initialized=false;
8382
	public function init($config)
8383
	{
8384
		$application=$this->getApplication();
8385
		if($this->_basePath===null)
8386
			$this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
8387
		if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
8388
			throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
8389
		if($this->_baseUrl===null)
8390
			$this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
8391
		$application->setAssetManager($this);
8392
		$this->_initialized=true;
8393
	}
8394
	public function getBasePath()
8395
	{
8396
		return $this->_basePath;
8397
	}
8398
	public function setBasePath($value)
8399
	{
8400
		if($this->_initialized)
8401
			throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
8402
		else
8403
		{
8404
			$this->_basePath=Prado::getPathOfNamespace($value);
8405
			if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
8406
				throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value);
8407
		}
8408
	}
8409
	public function getBaseUrl()
8410
	{
8411
		return $this->_baseUrl;
8412
	}
8413
	public function setBaseUrl($value)
8414
	{
8415
		if($this->_initialized)
8416
			throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
8417
		else
8418
			$this->_baseUrl=rtrim($value,'/');
8419
	}
8420
	public function publishFilePath($path,$checkTimestamp=false)
8421
	{
8422
		if(isset($this->_published[$path]))
8423
			return $this->_published[$path];
8424
		else if(empty($path) || ($fullpath=realpath($path))===false)
8425
			throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
8426
		else if(is_file($fullpath))
8427
		{
8428
			$dir=$this->hash(dirname($fullpath));
8429
			$fileName=basename($fullpath);
8430
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
8431
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
8432
				$this->copyFile($fullpath,$dst);
8433
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
8434
		}
8435
		else
8436
		{
8437
			$dir=$this->hash($fullpath);
8438
			if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
8439
			{
8440
				$this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
8441
			}
8442
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
8443
		}
8444
	}
8445
	public function getPublishedPath($path)
8446
	{
8447
		$path=realpath($path);
8448
		if(is_file($path))
8449
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
8450
		else
8451
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
8452
	}
8453
	public function getPublishedUrl($path)
8454
	{
8455
		$path=realpath($path);
8456
		if(is_file($path))
8457
			return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
8458
		else
8459
			return $this->_baseUrl.'/'.$this->hash($path);
8460
	}
8461
	protected function hash($dir)
8462
	{
8463
		return sprintf('%x',crc32($dir.Prado::getVersion()));
8464
	}
8465
	protected function copyFile($src,$dst)
8466
	{
8467
		if(!is_dir($dst))
8468
		{
8469
			@mkdir($dst);
8470
			@chmod($dst, PRADO_CHMOD);
8471
		}
8472
		$dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
8473
		if(@filemtime($dstFile)<@filemtime($src))
8474
		{
8475
			@copy($src,$dstFile);
8476
		}
8477
	}
8478
	public function copyDirectory($src,$dst)
8479
	{
8480
		if(!is_dir($dst))
8481
		{
8482
			@mkdir($dst);
8483
			@chmod($dst, PRADO_CHMOD);
8484
		}
8485
		if($folder=@opendir($src))
8486
		{
8487
			while($file=@readdir($folder))
8488
			{
8489
				if($file==='.' || $file==='..' || $file==='.svn')
8490
					continue;
8491
				else if(is_file($src.DIRECTORY_SEPARATOR.$file))
8492
				{
8493
					if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
8494
					{
8495
						@copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
8496
						@chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
8497
					}
8498
				}
8499
				else
8500
					$this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
8501
			}
8502
			closedir($folder);
8503
		} else {
8504
			throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
8505
		}
8506
	}
8507
	public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
8508
	{
8509
		if(isset($this->_published[$md5sum]))
8510
			return $this->_published[$md5sum];
8511
		else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
8512
			throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
8513
		else
8514
		{
8515
			$dir=$this->hash(dirname($fullpath));
8516
			$fileName=basename($fullpath);
8517
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
8518
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
8519
			{
8520
				if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
8521
				{
8522
					$this->copyFile($fullpath,$dst);
8523
					$this->deployTarFile($tarfile,$dst);
8524
				}
8525
			}
8526
			return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
8527
		}
8528
	}
8529
	protected function deployTarFile($path,$destination)
8530
	{
8531
		if(($fullpath=realpath($path))===false || !is_file($fullpath))
8532
			throw new TIOException('assetmanager_tarfile_invalid',$path);
8533
		else
8534
		{
8535
			Prado::using('System.IO.TTarFileExtractor');
8536
			$tar = new TTarFileExtractor($fullpath);
8537
			return $tar->extract($destination);
8538
		}
8539
	}
8540
}
8541
class TGlobalization extends TModule
8542
{
8543
	private $_defaultCharset = 'UTF-8';
8544
	private $_defaultCulture = 'en';
8545
	private $_charset=null;
8546
	private $_culture=null;
8547
	private $_translation;
8548
	public function init($xml)
8549
	{
8550
		if($this->_charset===null)
8551
			$this->_charset=$this->getDefaultCharset();
8552
		if($this->_culture===null)
8553
			$this->_culture=$this->getDefaultCulture();
8554
		if($xml!==null)
8555
		{
8556
			$translation = $xml->getElementByTagName('translation');
8557
			if($translation)
8558
				$this->setTranslationConfiguration($translation->getAttributes());
8559
		}
8560
		$this->getApplication()->setGlobalization($this);
8561
	}
8562
	public function getDefaultCulture()
8563
	{
8564
		return $this->_defaultCulture;
8565
	}
8566
	public function setDefaultCulture($culture)
8567
	{
8568
		$this->_defaultCulture = str_replace('-','_',$culture);
8569
	}
8570
	public function getDefaultCharset()
8571
	{
8572
		return $this->_defaultCharset;
8573
	}
8574
	public function setDefaultCharset($charset)
8575
	{
8576
		$this->_defaultCharset = $charset;
8577
	}
8578
	public function getCulture()
8579
	{
8580
		return $this->_culture;
8581
	}
8582
	public function setCulture($culture)
8583
	{
8584
		$this->_culture = str_replace('-','_',$culture);
8585
	}
8586
	public function getCharset()
8587
	{
8588
		return $this->_charset;
8589
	}
8590
	public function setCharset($charset)
8591
	{
8592
		$this->_charset = $charset;
8593
	}
8594
	public function getTranslationConfiguration()
8595
	{
8596
		return $this->_translation;
8597
	}
8598
	protected function setTranslationConfiguration(TMap $config)
8599
	{
8600
		if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
8601
		{
8602
			if($config['source'])
8603
			{
8604
				$config['source'] = Prado::getPathOfNamespace($config['source']);
8605
				if(!is_dir($config['source']))
8606
				{
8607
					if(@mkdir($config['source'])===false)
8608
					throw new TConfigurationException('globalization_source_path_failed',
8609
						$config['source']);
8610
					chmod($config['source'], PRADO_CHMOD);
8611
				}
8612
			}
8613
			else
8614
			{
8615
				throw new TConfigurationException("invalid source dir '{$config['source']}'");
8616
			}
8617
		}
8618
		if($config['cache'])
8619
		{
8620
			$config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
8621
			if(!is_dir($config['cache']))
8622
			{
8623
				if(@mkdir($config['cache'])===false)
8624
					throw new TConfigurationException('globalization_cache_path_failed',
8625
						$config['cache']);
8626
				chmod($config['cache'], PRADO_CHMOD);
8627
			}
8628
		}
8629
		$this->_translation = $config;
8630
	}
8631
	public function getTranslationCatalogue()
8632
	{
8633
		return $this->_translation['catalogue'];
8634
	}
8635
	public function setTranslationCatalogue($value)
8636
	{
8637
		$this->_translation['catalogue'] = $value;
8638
	}
8639
	public function getCultureVariants($culture=null)
8640
	{
8641
		if(is_null($culture)) $culture = $this->getCulture();
8642
		$variants = explode('_', $culture);
8643
		$result = array();
8644
		for(; count($variants) > 0; array_pop($variants))
8645
			$result[] = implode('_', $variants);
8646
		return $result;
8647
	}
8648
	public function getLocalizedResource($file,$culture=null)
8649
	{
8650
		$files = array();
8651
		$variants = $this->getCultureVariants($culture);
8652
		$path = pathinfo($file);
8653
		foreach($variants as $variant)
8654
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename'];
8655
		$filename = substr($path['basename'],0,strrpos($path['basename'],'.'));
8656
		foreach($variants as $variant)
8657
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension'];
8658
		$files[] = $file;
8659
		return $files;
8660
	}
8661
}
8662
class TApplication extends TComponent
8663
{
8664
	const STATE_OFF='Off';
8665
	const STATE_DEBUG='Debug';
8666
	const STATE_NORMAL='Normal';
8667
	const STATE_PERFORMANCE='Performance';
8668
	const PAGE_SERVICE_ID='page';
8669
	const CONFIG_FILE='application.xml';
8670
	const CONFIG_FILE_EXT='.xml';
8671
	const RUNTIME_PATH='runtime';
8672
	const CONFIGCACHE_FILE='config.cache';
8673
	const GLOBAL_FILE='global.cache';
8674
	private static $_steps=array(
8675
		'onBeginRequest',
8676
		'onLoadState',
8677
		'onLoadStateComplete',
8678
		'onAuthentication',
8679
		'onAuthenticationComplete',
8680
		'onAuthorization',
8681
		'onAuthorizationComplete',
8682
		'onPreRunService',
8683
		'runService',
8684
		'onSaveState',
8685
		'onSaveStateComplete',
8686
		'onPreFlushOutput',
8687
		'flushOutput'
8688
	);
8689
	private $_id;
8690
	private $_uniqueID;
8691
	private $_requestCompleted=false;
8692
	private $_step;
8693
	private $_services;
8694
	private $_service;
8695
	private $_modules=array();
8696
	private $_parameters;
8697
	private $_configFile;
8698
	private $_basePath;
8699
	private $_runtimePath;
8700
	private $_stateChanged=false;
8701
	private $_globals=array();
8702
	private $_cacheFile;
8703
	private $_errorHandler;
8704
	private $_request;
8705
	private $_response;
8706
	private $_session;
8707
	private $_cache;
8708
	private $_statePersister;
8709
	private $_user;
8710
	private $_globalization;
8711
	private $_security;
8712
	private $_assetManager;
8713
	private $_authRules;
8714
	private $_mode=TApplicationMode::Debug;
8715
	private $_pageServiceID = self::PAGE_SERVICE_ID;
8716
	public function __construct($basePath='protected',$cacheConfig=true)
8717
	{
8718
				Prado::setApplication($this);
8719
		$this->resolvePaths($basePath);
8720
		if($cacheConfig)
8721
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
8722
				$this->_uniqueID=md5($this->_runtimePath);
8723
		$this->_parameters=new TMap;
8724
		$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
8725
		Prado::setPathOfAlias('Application',$this->_basePath);
8726
	}
8727
	protected function resolvePaths($basePath)
8728
	{
8729
				if(empty($basePath) || ($basePath=realpath($basePath))===false)
8730
			throw new TConfigurationException('application_basepath_invalid',$basePath);
8731
		if(is_file($basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE))
8732
			$configFile=$basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE;
8733
		else if(is_file($basePath))
8734
		{
8735
			$configFile=$basePath;
8736
			$basePath=dirname($configFile);
8737
		}
8738
		else
8739
			$configFile=null;
8740
				$runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
8741
		if(is_writable($runtimePath))
8742
		{
8743
			if($configFile!==null)
8744
			{
8745
				$runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
8746
				if(!is_dir($runtimePath))
8747
				{
8748
					if(@mkdir($runtimePath)===false)
8749
						throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
8750
					@chmod($runtimePath, PRADO_CHMOD); 				}
8751
				$this->setConfigurationFile($configFile);
8752
			}
8753
			$this->setBasePath($basePath);
8754
			$this->setRuntimePath($runtimePath);
8755
		}
8756
		else
8757
			throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
8758
	}
8759
	public function run()
8760
	{
8761
		try
8762
		{
8763
			$this->initApplication();
8764
			$n=count(self::$_steps);
8765
			$this->_step=0;
8766
			$this->_requestCompleted=false;
8767
			while($this->_step<$n)
8768
			{
8769
				if($this->_mode===self::STATE_OFF)
8770
					throw new THttpException(503,'application_unavailable');
8771
				if($this->_requestCompleted)
8772
					break;
8773
				$method=self::$_steps[$this->_step];
8774
				$this->$method();
8775
				$this->_step++;
8776
			}
8777
		}
8778
		catch(Exception $e)
8779
		{
8780
			$this->onError($e);
8781
		}
8782
		$this->onEndRequest();
8783
	}
8784
	public function completeRequest()
8785
	{
8786
		$this->_requestCompleted=true;
8787
	}
8788
	public function getRequestCompleted()
8789
	{
8790
		return $this->_requestCompleted;
8791
	}
8792
	public function getGlobalState($key,$defaultValue=null)
8793
	{
8794
		return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
8795
	}
8796
	public function setGlobalState($key,$value,$defaultValue=null)
8797
	{
8798
		$this->_stateChanged=true;
8799
		if($value===$defaultValue)
8800
			unset($this->_globals[$key]);
8801
		else
8802
			$this->_globals[$key]=$value;
8803
	}
8804
	public function clearGlobalState($key)
8805
	{
8806
		$this->_stateChanged=true;
8807
		unset($this->_globals[$key]);
8808
	}
8809
	protected function loadGlobals()
8810
	{
8811
		$this->_globals=$this->getApplicationStatePersister()->load();
8812
	}
8813
	protected function saveGlobals()
8814
	{
8815
		if($this->_stateChanged)
8816
		{
8817
			$this->_stateChanged=false;
8818
			$this->getApplicationStatePersister()->save($this->_globals);
8819
		}
8820
	}
8821
	public function getID()
8822
	{
8823
		return $this->_id;
8824
	}
8825
	public function setID($value)
8826
	{
8827
		$this->_id=$value;
8828
	}
8829
	public function getPageServiceID()
8830
	{
8831
		return $this->_pageServiceID;
8832
	}
8833
	public function setPageServiceID($value)
8834
	{
8835
		$this->_pageServiceID=$value;
8836
	}
8837
	public function getUniqueID()
8838
	{
8839
		return $this->_uniqueID;
8840
	}
8841
	public function getMode()
8842
	{
8843
		return $this->_mode;
8844
	}
8845
	public function setMode($value)
8846
	{
8847
		$this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
8848
	}
8849
	public function getBasePath()
8850
	{
8851
		return $this->_basePath;
8852
	}
8853
	public function setBasePath($value)
8854
	{
8855
		$this->_basePath=$value;
8856
	}
8857
	public function getConfigurationFile()
8858
	{
8859
		return $this->_configFile;
8860
	}
8861
	public function setConfigurationFile($value)
8862
	{
8863
		$this->_configFile=$value;
8864
	}
8865
	public function getRuntimePath()
8866
	{
8867
		return $this->_runtimePath;
8868
	}
8869
	public function setRuntimePath($value)
8870
	{
8871
		$this->_runtimePath=$value;
8872
		if($this->_cacheFile)
8873
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
8874
				$this->_uniqueID=md5($this->_runtimePath);
8875
	}
8876
	public function getService()
8877
	{
8878
		return $this->_service;
8879
	}
8880
	public function setService($value)
8881
	{
8882
		$this->_service=$value;
8883
	}
8884
	public function setModule($id,IModule $module)
8885
	{
8886
		if(isset($this->_modules[$id]))
8887
			throw new TConfigurationException('application_moduleid_duplicated',$id);
8888
		else
8889
			$this->_modules[$id]=$module;
8890
	}
8891
	public function getModule($id)
8892
	{
8893
		return isset($this->_modules[$id])?$this->_modules[$id]:null;
8894
	}
8895
	public function getModules()
8896
	{
8897
		return $this->_modules;
8898
	}
8899
	public function getParameters()
8900
	{
8901
		return $this->_parameters;
8902
	}
8903
	public function getRequest()
8904
	{
8905
		if(!$this->_request)
8906
		{
8907
			$this->_request=new THttpRequest;
8908
			$this->_request->init(null);
8909
		}
8910
		return $this->_request;
8911
	}
8912
	public function setRequest(THttpRequest $request)
8913
	{
8914
		$this->_request=$request;
8915
	}
8916
	public function getResponse()
8917
	{
8918
		if(!$this->_response)
8919
		{
8920
			$this->_response=new THttpResponse;
8921
			$this->_response->init(null);
8922
		}
8923
		return $this->_response;
8924
	}
8925
	public function setResponse(THttpResponse $response)
8926
	{
8927
		$this->_response=$response;
8928
	}
8929
	public function getSession()
8930
	{
8931
		if(!$this->_session)
8932
		{
8933
			$this->_session=new THttpSession;
8934
			$this->_session->init(null);
8935
		}
8936
		return $this->_session;
8937
	}
8938
	public function setSession(THttpSession $session)
8939
	{
8940
		$this->_session=$session;
8941
	}
8942
	public function getErrorHandler()
8943
	{
8944
		if(!$this->_errorHandler)
8945
		{
8946
			$this->_errorHandler=new TErrorHandler;
8947
			$this->_errorHandler->init(null);
8948
		}
8949
		return $this->_errorHandler;
8950
	}
8951
	public function setErrorHandler(TErrorHandler $handler)
8952
	{
8953
		$this->_errorHandler=$handler;
8954
	}
8955
	public function getSecurityManager()
8956
	{
8957
		if(!$this->_security)
8958
		{
8959
			$this->_security=new TSecurityManager;
8960
			$this->_security->init(null);
8961
		}
8962
		return $this->_security;
8963
	}
8964
	public function setSecurityManager(TSecurityManager $sm)
8965
	{
8966
		$this->_security=$sm;
8967
	}
8968
	public function getAssetManager()
8969
	{
8970
		if(!$this->_assetManager)
8971
		{
8972
			$this->_assetManager=new TAssetManager;
8973
			$this->_assetManager->init(null);
8974
		}
8975
		return $this->_assetManager;
8976
	}
8977
	public function setAssetManager(TAssetManager $value)
8978
	{
8979
		$this->_assetManager=$value;
8980
	}
8981
	public function getApplicationStatePersister()
8982
	{
8983
		if(!$this->_statePersister)
8984
		{
8985
			$this->_statePersister=new TApplicationStatePersister;
8986
			$this->_statePersister->init(null);
8987
		}
8988
		return $this->_statePersister;
8989
	}
8990
	public function setApplicationStatePersister(IStatePersister $persister)
8991
	{
8992
		$this->_statePersister=$persister;
8993
	}
8994
	public function getCache()
8995
	{
8996
		return $this->_cache;
8997
	}
8998
	public function setCache(ICache $cache)
8999
	{
9000
		$this->_cache=$cache;
9001
	}
9002
	public function getUser()
9003
	{
9004
		return $this->_user;
9005
	}
9006
	public function setUser(IUser $user)
9007
	{
9008
		$this->_user=$user;
9009
	}
9010
	public function getGlobalization($createIfNotExists=true)
9011
	{
9012
		if($this->_globalization===null && $createIfNotExists)
9013
			$this->_globalization=new TGlobalization;
9014
		return $this->_globalization;
9015
	}
9016
	public function setGlobalization(TGlobalization $glob)
9017
	{
9018
		$this->_globalization=$glob;
9019
	}
9020
	public function getAuthorizationRules()
9021
	{
9022
		if($this->_authRules===null)
9023
			$this->_authRules=new TAuthorizationRuleCollection;
9024
		return $this->_authRules;
9025
	}
9026
	public function applyConfiguration($config,$withinService=false)
9027
	{
9028
		if($config->getIsEmpty())
9029
			return;
9030
				foreach($config->getAliases() as $alias=>$path)
9031
			Prado::setPathOfAlias($alias,$path);
9032
		foreach($config->getUsings() as $using)
9033
			Prado::using($using);
9034
				if(!$withinService)
9035
		{
9036
			foreach($config->getProperties() as $name=>$value)
9037
				$this->setSubProperty($name,$value);
9038
		}
9039
		if(empty($this->_services))
9040
			$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
9041
				foreach($config->getParameters() as $id=>$parameter)
9042
		{
9043
			if(is_array($parameter))
9044
			{
9045
				$component=Prado::createComponent($parameter[0]);
9046
				foreach($parameter[1] as $name=>$value)
9047
					$component->setSubProperty($name,$value);
9048
				$this->_parameters->add($id,$component);
9049
			}
9050
			else
9051
				$this->_parameters->add($id,$parameter);
9052
		}
9053
				$modules=array();
9054
		foreach($config->getModules() as $id=>$moduleConfig)
9055
		{
9056
			list($moduleClass, $initProperties, $configElement)=$moduleConfig;
9057
			$module=Prado::createComponent($moduleClass);
9058
			if(!is_string($id))
9059
			{
9060
				$id='_module'.count($this->_modules);
9061
				$initProperties['id']=$id;
9062
			}
9063
			$this->setModule($id,$module);
9064
			foreach($initProperties as $name=>$value)
9065
				$module->setSubProperty($name,$value);
9066
			$modules[]=array($module,$configElement);
9067
		}
9068
		foreach($modules as $module)
9069
			$module[0]->init($module[1]);
9070
				foreach($config->getServices() as $serviceID=>$serviceConfig)
9071
			$this->_services[$serviceID]=$serviceConfig;
9072
				foreach($config->getExternalConfigurations() as $filePath=>$condition)
9073
		{
9074
			if($condition!==true)
9075
				$condition=$this->evaluateExpression($condition);
9076
			if($condition)
9077
			{
9078
				if(($path=Prado::getPathOfNamespace($filePath,self::CONFIG_FILE_EXT))===null || !is_file($path))
9079
					throw new TConfigurationException('application_includefile_invalid',$filePath);
9080
				$c=new TApplicationConfiguration;
9081
				$c->loadFromFile($path);
9082
				$this->applyConfiguration($c,$withinService);
9083
			}
9084
		}
9085
	}
9086
	protected function initApplication()
9087
	{
9088
		if($this->_configFile!==null)
9089
		{
9090
			if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
9091
			{
9092
				$config=new TApplicationConfiguration;
9093
				$config->loadFromFile($this->_configFile);
9094
				if($this->_cacheFile!==null)
9095
					file_put_contents($this->_cacheFile,Prado::serialize($config),LOCK_EX);
9096
			}
9097
			else
9098
				$config=Prado::unserialize(file_get_contents($this->_cacheFile));
9099
			$this->applyConfiguration($config,false);
9100
		}
9101
		if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
9102
			$serviceID=$this->getPageServiceID();
9103
		$this->startService($serviceID);
9104
	}
9105
	public function startService($serviceID)
9106
	{
9107
		if(isset($this->_services[$serviceID]))
9108
		{
9109
			list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
9110
			$service=Prado::createComponent($serviceClass);
9111
			if(!($service instanceof IService))
9112
				throw new THttpException(500,'application_service_invalid',$serviceClass);
9113
			if(!$service->getEnabled())
9114
				throw new THttpException(500,'application_service_unavailable',$serviceClass);
9115
			$service->setID($serviceID);
9116
			$this->setService($service);
9117
			foreach($initProperties as $name=>$value)
9118
				$service->setSubProperty($name,$value);
9119
			if($configElement!==null)
9120
			{
9121
				$config=new TApplicationConfiguration;
9122
				$config->loadFromXml($configElement,$this->getBasePath());
9123
				$this->applyConfiguration($config,true);
9124
			}
9125
			$service->init($configElement);
9126
		}
9127
		else
9128
			throw new THttpException(500,'application_service_unknown',$serviceID);
9129
	}
9130
	public function onError($param)
9131
	{
9132
		Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
9133
		$this->raiseEvent('OnError',$this,$param);
9134
		$this->getErrorHandler()->handleError($this,$param);
9135
	}
9136
	public function onBeginRequest()
9137
	{
9138
		$this->raiseEvent('OnBeginRequest',$this,null);
9139
	}
9140
	public function onAuthentication()
9141
	{
9142
		$this->raiseEvent('OnAuthentication',$this,null);
9143
	}
9144
	public function onAuthenticationComplete()
9145
	{
9146
		$this->raiseEvent('OnAuthenticationComplete',$this,null);
9147
	}
9148
	public function onAuthorization()
9149
	{
9150
		$this->raiseEvent('OnAuthorization',$this,null);
9151
	}
9152
	public function onAuthorizationComplete()
9153
	{
9154
		$this->raiseEvent('OnAuthorizationComplete',$this,null);
9155
	}
9156
	public function onLoadState()
9157
	{
9158
		$this->loadGlobals();
9159
		$this->raiseEvent('OnLoadState',$this,null);
9160
	}
9161
	public function onLoadStateComplete()
9162
	{
9163
		$this->raiseEvent('OnLoadStateComplete',$this,null);
9164
	}
9165
	public function onPreRunService()
9166
	{
9167
		$this->raiseEvent('OnPreRunService',$this,null);
9168
	}
9169
	public function runService()
9170
	{
9171
		if($this->_service)
9172
			$this->_service->run();
9173
	}
9174
	public function onSaveState()
9175
	{
9176
		$this->raiseEvent('OnSaveState',$this,null);
9177
		$this->saveGlobals();
9178
	}
9179
	public function onSaveStateComplete()
9180
	{
9181
		$this->raiseEvent('OnSaveStateComplete',$this,null);
9182
	}
9183
	public function onPreFlushOutput()
9184
	{
9185
		$this->raiseEvent('OnPreFlushOutput',$this,null);
9186
	}
9187
	public function flushOutput()
9188
	{
9189
		$this->getResponse()->flush();
9190
	}
9191
	public function onEndRequest()
9192
	{
9193
		$this->saveGlobals();  		$this->raiseEvent('OnEndRequest',$this,null);
9194
	}
9195
}
9196
class TApplicationMode extends TEnumerable
9197
{
9198
	const Off='Off';
9199
	const Debug='Debug';
9200
	const Normal='Normal';
9201
	const Performance='Performance';
9202
}
9203
class TApplicationConfiguration extends TComponent
9204
{
9205
	private $_properties=array();
9206
	private $_usings=array();
9207
	private $_aliases=array();
9208
	private $_modules=array();
9209
	private $_services=array();
9210
	private $_parameters=array();
9211
	private $_includes=array();
9212
	private $_empty=true;
9213
	public function loadFromFile($fname)
9214
	{
9215
		$dom=new TXmlDocument;
9216
		$dom->loadFromFile($fname);
9217
		$this->loadFromXml($dom,dirname($fname));
9218
	}
9219
	public function getIsEmpty()
9220
	{
9221
		return $this->_empty;
9222
	}
9223
	public function loadFromXml($dom,$configPath)
9224
	{
9225
				foreach($dom->getAttributes() as $name=>$value)
9226
		{
9227
			$this->_properties[$name]=$value;
9228
			$this->_empty=false;
9229
		}
9230
		foreach($dom->getElements() as $element)
9231
		{
9232
			switch($element->getTagName())
9233
			{
9234
				case 'paths':
9235
					$this->loadPathsXml($element,$configPath);
9236
					break;
9237
				case 'modules':
9238
					$this->loadModulesXml($element,$configPath);
9239
					break;
9240
				case 'services':
9241
					$this->loadServicesXml($element,$configPath);
9242
					break;
9243
				case 'parameters':
9244
					$this->loadParametersXml($element,$configPath);
9245
					break;
9246
				case 'include':
9247
					$this->loadExternalXml($element,$configPath);
9248
					break;
9249
				default:
9250
										break;
9251
			}
9252
		}
9253
	}
9254
	protected function loadPathsXml($pathsNode,$configPath)
9255
	{
9256
		foreach($pathsNode->getElements() as $element)
9257
		{
9258
			switch($element->getTagName())
9259
			{
9260
				case 'alias':
9261
				{
9262
					if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
9263
					{
9264
						$path=str_replace('\\','/',$path);
9265
						if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))								$p=realpath($path);
9266
						else
9267
							$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
9268
						if($p===false || !is_dir($p))
9269
							throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
9270
						if(isset($this->_aliases[$id]))
9271
							throw new TConfigurationException('appconfig_alias_redefined',$id);
9272
						$this->_aliases[$id]=$p;
9273
					}
9274
					else
9275
						throw new TConfigurationException('appconfig_alias_invalid');
9276
					$this->_empty=false;
9277
					break;
9278
				}
9279
				case 'using':
9280
				{
9281
					if(($namespace=$element->getAttribute('namespace'))!==null)
9282
						$this->_usings[]=$namespace;
9283
					else
9284
						throw new TConfigurationException('appconfig_using_invalid');
9285
					$this->_empty=false;
9286
					break;
9287
				}
9288
				default:
9289
					throw new TConfigurationException('appconfig_paths_invalid',$tagName);
9290
			}
9291
		}
9292
	}
9293
	protected function loadModulesXml($modulesNode,$configPath)
9294
	{
9295
		foreach($modulesNode->getElements() as $element)
9296
		{
9297
			if($element->getTagName()==='module')
9298
			{
9299
				$properties=$element->getAttributes();
9300
				$id=$properties->itemAt('id');
9301
				$type=$properties->remove('class');
9302
				if($type===null)
9303
					throw new TConfigurationException('appconfig_moduletype_required',$id);
9304
				$element->setParent(null);
9305
				if($id===null)
9306
					$this->_modules[]=array($type,$properties->toArray(),$element);
9307
				else
9308
					$this->_modules[$id]=array($type,$properties->toArray(),$element);
9309
				$this->_empty=false;
9310
			}
9311
			else
9312
				throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
9313
		}
9314
	}
9315
	protected function loadServicesXml($servicesNode,$configPath)
9316
	{
9317
		foreach($servicesNode->getElements() as $element)
9318
		{
9319
			if($element->getTagName()==='service')
9320
			{
9321
				$properties=$element->getAttributes();
9322
				if(($id=$properties->itemAt('id'))===null)
9323
					throw new TConfigurationException('appconfig_serviceid_required');
9324
				if(($type=$properties->remove('class'))===null)
9325
					throw new TConfigurationException('appconfig_servicetype_required',$id);
9326
				$element->setParent(null);
9327
				$this->_services[$id]=array($type,$properties->toArray(),$element);
9328
				$this->_empty=false;
9329
			}
9330
			else
9331
				throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
9332
		}
9333
	}
9334
	protected function loadParametersXml($parametersNode,$configPath)
9335
	{
9336
		foreach($parametersNode->getElements() as $element)
9337
		{
9338
			if($element->getTagName()==='parameter')
9339
			{
9340
				$properties=$element->getAttributes();
9341
				if(($id=$properties->remove('id'))===null)
9342
					throw new TConfigurationException('appconfig_parameterid_required');
9343
				if(($type=$properties->remove('class'))===null)
9344
				{
9345
					if(($value=$properties->remove('value'))===null)
9346
						$this->_parameters[$id]=$element;
9347
					else
9348
						$this->_parameters[$id]=$value;
9349
				}
9350
				else
9351
					$this->_parameters[$id]=array($type,$properties->toArray());
9352
				$this->_empty=false;
9353
			}
9354
			else
9355
				throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
9356
		}
9357
	}
9358
	protected function loadExternalXml($includeNode,$configPath)
9359
	{
9360
		if(($when=$includeNode->getAttribute('when'))===null)
9361
			$when=true;
9362
		if(($filePath=$includeNode->getAttribute('file'))===null)
9363
			throw new TConfigurationException('appconfig_includefile_required');
9364
		if(isset($this->_includes[$filePath]))
9365
			$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
9366
		else
9367
			$this->_includes[$filePath]=$when;
9368
		$this->_empty=false;
9369
	}
9370
	public function getProperties()
9371
	{
9372
		return $this->_properties;
9373
	}
9374
	public function getAliases()
9375
	{
9376
		return $this->_aliases;
9377
	}
9378
	public function getUsings()
9379
	{
9380
		return $this->_usings;
9381
	}
9382
	public function getModules()
9383
	{
9384
		return $this->_modules;
9385
	}
9386
	public function getServices()
9387
	{
9388
		return $this->_services;
9389
	}
9390
	public function getParameters()
9391
	{
9392
		return $this->_parameters;
9393
	}
9394
	public function getExternalConfigurations()
9395
	{
9396
		return $this->_includes;
9397
	}
9398
}
9399
class TApplicationStatePersister extends TModule implements IStatePersister
9400
{
9401
	const CACHE_NAME='prado:appstate';
9402
	public function init($config)
9403
	{
9404
		$this->getApplication()->setApplicationStatePersister($this);
9405
	}
9406
	protected function getStateFilePath()
9407
	{
9408
		return $this->getApplication()->getRuntimePath().'/global.cache';
9409
	}
9410
	public function load()
9411
	{
9412
		if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
9413
			return unserialize($value);
9414
		else
9415
		{
9416
			if(($content=@file_get_contents($this->getStateFilePath()))!==false)
9417
				return unserialize($content);
9418
			else
9419
				return null;
9420
		}
9421
	}
9422
	public function save($state)
9423
	{
9424
		$content=serialize($state);
9425
		$saveFile=true;
9426
		if(($cache=$this->getApplication()->getCache())!==null)
9427
		{
9428
			if($cache->get(self::CACHE_NAME)===$content)
9429
				$saveFile=false;
9430
			else
9431
				$cache->set(self::CACHE_NAME,$content);
9432
		}
9433
		if($saveFile)
9434
		{
9435
			$fileName=$this->getStateFilePath();
9436
			file_put_contents($fileName,$content,LOCK_EX);
9437
		}
9438
	}
9439
}
9440
class TShellApplication extends TApplication
9441
{
9442
	public function run()
9443
	{
9444
		$this->initApplication();
9445
	}
9446
}
9447
?>