diff options
| author | godzilla80@gmx.net <> | 2010-02-14 01:22:57 +0000 | 
|---|---|---|
| committer | godzilla80@gmx.net <> | 2010-02-14 01:22:57 +0000 | 
| commit | 94e94e0a8566f23d16658a04c55b0bbfdd6689aa (patch) | |
| tree | 72ffad82c279080dd9320d45dda26d64ffb4626f | |
| parent | 966fd66f217911d079c4bd6a87b09f4a0c5c4736 (diff) | |
Merge Branches & Trunk
/trunk:r2680,2692,2707-2736
/branches/3.1:r2682-2686,2694-2702,2705,2738-2762
50 files changed, 10294 insertions, 186 deletions
diff --git a/.gitattributes b/.gitattributes index 868a31ba..964ffa6d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2896,6 +2896,7 @@ framework/powered2.gif -text  framework/prado-cli -text  framework/prado-cli.bat -text  framework/prado.php -text +framework/pradolite.php -text  /index.html -text  /phing -text  /phing.bat -text @@ -3127,6 +3128,8 @@ tests/FunctionalTests/tickets/protected/messages/en/messages.xml -text  tests/FunctionalTests/tickets/protected/pages/DActiveDropDownList2.php -text  tests/FunctionalTests/tickets/protected/pages/Issue120.page -text  tests/FunctionalTests/tickets/protected/pages/Issue120.php -text +tests/FunctionalTests/tickets/protected/pages/Issue216.page -text +tests/FunctionalTests/tickets/protected/pages/Issue216.php -text  tests/FunctionalTests/tickets/protected/pages/Layout.php -text  tests/FunctionalTests/tickets/protected/pages/Layout.tpl -text  tests/FunctionalTests/tickets/protected/pages/TestHtmlArea.php -text @@ -3301,6 +3304,7 @@ tests/FunctionalTests/tickets/protected700/pages/admin/users/config.xml -text  tests/FunctionalTests/tickets/protected700/pages/config.xml -text  tests/FunctionalTests/tickets/protected700/pages/content/Home.page -text  tests/FunctionalTests/tickets/tests/Issue120TestCase.php -text +tests/FunctionalTests/tickets/tests/Issue216TestCase.php -text  tests/FunctionalTests/tickets/tests/Ticket121TestCase.php -text  tests/FunctionalTests/tickets/tests/Ticket163TestCase.php -text  tests/FunctionalTests/tickets/tests/Ticket169TestCase.php -text @@ -13,13 +13,46 @@ ENH: Issue#173 - Add "dragdropextra" (superghosting) patch, mouse coordinates an  NEW: Add TActiveMultiView (LCS Team)  NEW: Beta of master/slave senario solution (Yves) -Version 3.1.6 to be released +Version 3.1.7 To be released +ENH: Issue#24  - Specify needed fields on demand (Yves)  +BUG: Issue#80  - Inconsistencies in TRegularExpressionValidator (Christophe) +BUG: Issue#86  - THttpSession.CookieMode ignored / Session ID leak (Christophe) +BUG: Issue#94  - DataGrid header/footer renderers unable to locate their parent grid in setData() method (Christophe) +BUG: Issue#151 - TTextBox fails to display inital line break (Yves) +BUG: Issue#153 - Bug with calls like MyActiveRedorc->withText()->withUser()->find(...) and null result (Christophe) +BUG: Issue#157 - Enabled does not work properly on TActiveRadioButton/CheckBoxList controls (Bradley, Carl) +BUG: Issue#166 - E_NOTICE level error in TDataGatewayCommand (Carl) +BUG: Issue#169 - FlushOnExecute on Basic CacheModel flushes all Application Cache (E.Letard, Christophe) +BUG: Issue#171 - <connection> tag in SqlMap config ignored in 3.1.5 and above, introduced by solving Issue#68 (Yves) +EHN: Issue#184 - THttpResponse doesn't support custom Content-Type headers, remove charset part of header if THttpResponse.Charset=false (Yves) +BUG: Issue#188 - TDbCache doesn't check if db connection is active. (Yves) +BUG: Issue#189 - Page State corrupted when EnableStateValidation=False (Christophe) +BUG: Issue#191 - Bad parsing of MySQL ENUM type column (Yves) +BUG: Issue#192 - soap-enc:Array not a valid complex type (mosonyi at esix.hu) +BUG: Issue#198 - "Undefined variable: tagName" after error in application configuration. (Christophe) +BUG: Issue#200 - TShellApplication failed when no service are defined in application configuration. (Christophe) +BUG: Issue#208 - TDbConnection.Charset not working properly (googlenew at pcforum.hu, Christophe) +BUG: Issue#212 - Mistaken query executed by TMysqlMetaData (pbenny, Christophe) +BUG: Issue#216 - TTabPanel doesn't preserve active tab on callback request (googlenew at pcforum.hu,Christophe) +BUG: Typo in TBoundColumn (Robin) +BUG: TActiveDatePicker js error when date format does not have the 3 elements (Christophe) +ENH: Add property ClientScriptManagerClass to TPageService and releated changes in TPage.getClientScript() (Yves) +ENH: Always render clientside counterparts of validation control even if not enabled, but pass-through Enabled property, to allow Enabled/Disable of validator on callback. (Yves) +EHN: Add property TValidationSummary.ScrollToSummary to server-side control since property exists on client-side. (Yves) +EHN: Add property TransactionClass (defaults to System.Data.TDbTransaction) to TDbConnection and modify beginTransaction() (Yves) +ENH: Modify TDbTableInfo::getColumnNames() to store result in private class member (Yves) +ENH: Issue#215 - Add ClientSide property to TDropContainer (googlenew at pcforum.hu, Christophe) +CHG: Issue#218 - Change URL of Javascript Logger (Christophe) + +Version 3.1.6 July 22, 2009  BUG: Issue#98 - Missing file in quickstart demo (Chrisotphe) +BUG: Issue#105 - Enabling/disabling TFileUpload on TPanel (Carl)  BUG: Issue#115 - Clientside registry of serverside controls don't cover all controls: Prado.WebUI.TAutoComplete, Prado.WebUI.TInPlaceTextBox (Yves)  BUG: Issue#117 - Consider TValidationSummary.DisplayMode="HeaderOnly" if TValidationSummary.ShowMessageBox is set (Yves)  BUG: Issue#164 - CultureInfo::validCulture should be declared as a static method (Christophe)  BUG: Issue#168 - TSqlMapXmlConfiguration: CacheModel properties are not set (Yves)  BUG: Issue#172 - TDbCache fails to recognize need to re-create cache table (Yves) +BUG: Issue#178 - TActiveFileUpload progress indicator is misleading (Christophe, googlenew-at-pcforum.hu)  ENH: Issue#174 - TErrorHandler: HTTP error messages contains sensitive information (Yves)  ENH: Issue#175 - TBulletedList: Introduce TBulletStyle::None (Yves)  ENH: Issue#176 - THttpResponse::writeFile() add additional parameters to take more influence on behavior (forceDownload, clientFileName, fileSize), add png to defaultMimeTypes (Yves) @@ -28,6 +61,7 @@ ENH: TAssetManager: introduce protected property "Published" to allow subclasses  ENH: TFirePhpLogRoute: bypass to TBrowserLogRoute if headers already sent / php.ini (output_buffering=Off, implicit_flush=On) (Yves)  EHN: Performance optimization in PradoBase::createComponent() (Yves)  EHN: Add property TPage.EnableStateCompression and related modifications in TPageStateFormatter since it is unnecessary to compress clientstate if TCachePageStatePersister/TSessionPageStatePersister is used (Yves) +ENH: Add property CssClass to TBrowserLog otuput and hide inline CSS (Carl)  Version 3.1.5 May 24, 2009  BUG: Issue#55 - TPropertyAccess.get and has don't recognize magic getter __get (Yves) @@ -9,6 +9,13 @@ if you want to upgrade from version A to version C and there is  version B between A and C, you need to following the instructions  for both A and B. +Upgrading from v3.1.6 +--------------------- +- The different SQLMap cache engines (TSQLMapFifoCache, TSQLMapLRUCache, TSQLMapApplicationCache) doesn't +take anymore the cache size in their constructor. Instead, they take the cachemodel object who instanciated them. +It shouldn't affect existing code, except if you instanciate one of this cache directly (i.e, without a <cachemodel> +directive in your SQLMap configuration) +  Upgrading from v3.1.5  --------------------- diff --git a/buildscripts/texbuilder/quickstart/quickstart.tex b/buildscripts/texbuilder/quickstart/quickstart.tex index 2d45f17a..dbb30179 100644 --- a/buildscripts/texbuilder/quickstart/quickstart.tex +++ b/buildscripts/texbuilder/quickstart/quickstart.tex @@ -52,7 +52,7 @@  %----------------- TITLE -------------- -\title{\Huge \bfseries PRADO v3.1.6 Quickstart Tutorial +\title{\Huge \bfseries PRADO v3.2 Quickstart Tutorial      \thanks{Copyright 2004-2009. All Rights Reserved.}  }  \author{Qiang Xue and Wei Zhuo} diff --git a/demos/quickstart/protected/pages/Controls/JavascriptLogger.page b/demos/quickstart/protected/pages/Controls/JavascriptLogger.page index 3c7d0684..c2187632 100644 --- a/demos/quickstart/protected/pages/Controls/JavascriptLogger.page +++ b/demos/quickstart/protected/pages/Controls/JavascriptLogger.page @@ -4,7 +4,7 @@  <com:DocLink ClassPath="System.Web.UI.WebControls.TJavascriptLogger" />
  <p id="390277" class="block-content">
 -<tt>TJavascriptLogger</tt> provides logging for client-side javascript. It is mainly a wrapper of the Javascript developed at <a href="http://gleepglop.com/javascripts/logger/">http://gleepglop.com/javascripts/logger/</a>.
 +<tt>TJavascriptLogger</tt> provides logging for client-side javascript. It is mainly a wrapper of the Javascript developed at <a href="http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/">http://gleepglop.com/javascripts/logger/</a>.
  </p>
  <p id="390278" class="block-content">
 diff --git a/demos/quickstart/protected/pages/Controls/id/JavascriptLogger.page b/demos/quickstart/protected/pages/Controls/id/JavascriptLogger.page index 93be7d9b..4fb52ee5 100644 --- a/demos/quickstart/protected/pages/Controls/id/JavascriptLogger.page +++ b/demos/quickstart/protected/pages/Controls/id/JavascriptLogger.page @@ -4,7 +4,7 @@  <com:DocLink ClassPath="System.Web.UI.WebControls.TJavascriptLogger" />
  <p id="390277" class="block-content">
 -<tt>TJavascriptLogger</tt> menyediakan javascript pencatatan sisi-klien. Ini sebagian besar adalah pelapis dari Javascript yang dikembangkan di <a href="http://gleepglop.com/javascripts/logger/">http://gleepglop.com/javascripts/logger/</a>.
 +<tt>TJavascriptLogger</tt> menyediakan javascript pencatatan sisi-klien. Ini sebagian besar adalah pelapis dari Javascript yang dikembangkan di <a href="http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/">http://gleepglop.com/javascripts/logger/</a>.
  </p>
  <p id="390278" class="block-content">
 diff --git a/framework/3rdParty/WsdlGen/Wsdl.php b/framework/3rdParty/WsdlGen/Wsdl.php index 1df2f337..3ec5bdf1 100644 --- a/framework/3rdParty/WsdlGen/Wsdl.php +++ b/framework/3rdParty/WsdlGen/Wsdl.php @@ -148,15 +148,16 @@ class Wsdl  			$complexType->setAttribute('name', $type);  			if(substr($type, strlen($type) - 5, 5) == 'Array')  // if it's an array  			{ -				$complexContent = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:complexContent'); -				$restriction = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:restriction'); -				$restriction->setAttribute('base', 'soap-enc:Array'); -				$attribute = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:attribute'); -				$attribute->setAttribute('ref', "soap-enc:arrayType"); -				$attribute->setAttribute('wsdl:arrayType', $this->getArrayTypePrefix($type) . substr($type, 0, strlen($type) - 5) . '[]'); -				$restriction->appendChild($attribute); -				$complexContent->appendChild($restriction); -				$complexType->appendChild($complexContent); +				$sequence = $dom->createElement("xsd:sequence"); + +				$singularType = substr($type, 0, strlen($type) - 5); +				$e = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:element'); +				$e->setAttribute('name', $singularType); +				$e->setAttribute('type', sprintf('tns:%s',$singularType)); +				$e->setAttribute('minOccurs','0'); +				$e->setAttribute('maxOccurs','unbounded'); +				$sequence->appendChild($e); +				$complexType->appendChild($sequence);  			}  			else  			{ diff --git a/framework/3rdParty/readme.html b/framework/3rdParty/readme.html index bf9c243f..a25ec97a 100644 --- a/framework/3rdParty/readme.html +++ b/framework/3rdParty/readme.html @@ -99,7 +99,7 @@ projects.  </tr>
  <tr>
  	<td><a href="../Web/Javascripts/prado/logger/logger.js">../Web/Javascripts/prado/logger/logger.js</a></td>
 -	<td><a href="http://gleepglop.com/javascripts/logger/">http://gleepglop.com/javascripts/logger/</a> <a href="http://slayeroffice.com">http://slayeroffice.com</a></td>
 +	<td><a href="http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/">http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/</a> <a href="http://slayeroffice.com">http://slayeroffice.com</a></td>
  	<td>None</td>
  	<td>TJavascriptLogger</td>
  	<td>Javascript logger by Corey Johnson. Object Tree by S.G. Chipman.</td>
 diff --git a/framework/Caching/TDbCache.php b/framework/Caching/TDbCache.php index 8ea8eae9..0e013c79 100644 --- a/framework/Caching/TDbCache.php +++ b/framework/Caching/TDbCache.php @@ -183,7 +183,6 @@ class TDbCache extends TCache  	{
  		if($this->_cacheInitialized && !$force) return;
  		$db=$this->getDbConnection();
 -		$db->setActive(true);
  		try
  		{
  			$key = 'TDbCache:' . $this->_cacheTable . ':created';
 @@ -328,6 +327,8 @@ class TDbCache extends TCache  	{
  		if($this->_db===null)
  			$this->_db=$this->createDbConnection();
 +
 +		$this->_db->setActive(true);
  		return $this->_db;
  	}
 @@ -464,7 +465,7 @@ class TDbCache extends TCache  		if(!$this->_cacheInitialized) $this->initializeCache();
  		try {
  			$sql='SELECT value FROM '.$this->_cacheTable.' WHERE itemkey=\''.$key.'\' AND (expire=0 OR expire>'.time().') ORDER BY expire DESC';
 -			$command=$this->_db->createCommand($sql);
 +			$command=$this->getDbConnection()->createCommand($sql);
  			return $command->queryScalar();
  		}
  		catch(Exception $e)
 @@ -505,7 +506,7 @@ class TDbCache extends TCache  		$sql="INSERT INTO {$this->_cacheTable} (itemkey,value,expire) VALUES(:key,:value,$expire)";
  		try
  		{
 -			$command=$this->_db->createCommand($sql);
 +			$command=$this->getDbConnection()->createCommand($sql);
  			$command->bindValue(':key',$key,PDO::PARAM_STR);
  			$command->bindValue(':value',$value,PDO::PARAM_LOB);
  			$command->execute();
 @@ -537,7 +538,7 @@ class TDbCache extends TCache  		if(!$this->_cacheInitialized) $this->initializeCache();
  		try
  		{
 -			$command=$this->_db->createCommand("DELETE FROM {$this->_cacheTable} WHERE itemkey=:key");
 +			$command=$this->getDbConnection()->createCommand("DELETE FROM {$this->_cacheTable} WHERE itemkey=:key");
  			$command->bindValue(':key',$key,PDO::PARAM_STR);
  			$command->execute();
  			return true;
 @@ -559,7 +560,7 @@ class TDbCache extends TCache  		if(!$this->_cacheInitialized) $this->initializeCache();
  		try
  		{
 -			$command = $this->_db->createCommand("DELETE FROM {$this->_cacheTable}");
 +			$command = $this->getDbConnection()->createCommand("DELETE FROM {$this->_cacheTable}");
  			$command->execute();
  		}
  		catch(Exception $e)
 diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php index a3daf35c..7e584514 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php @@ -4,7 +4,7 @@   *
   * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System.Data.ActiveRecord.Relations
 @@ -85,6 +85,8 @@ abstract class TActiveRecordRelation  		}
  		else if($results instanceof TActiveRecordRelation)
  			$stack[] = $this; //call it later
 +		else if($results === null || !$validArray)
 +			$stacks=array();
  		return $results;
  	}
 diff --git a/framework/Data/Common/Mysql/TMysqlMetaData.php b/framework/Data/Common/Mysql/TMysqlMetaData.php index ae552cf3..fad33cea 100644 --- a/framework/Data/Common/Mysql/TMysqlMetaData.php +++ b/framework/Data/Common/Mysql/TMysqlMetaData.php @@ -4,7 +4,7 @@   *
   * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System.Data.Common.Mysql
 @@ -110,7 +110,7 @@ class TMysqlMetaData extends TDbMetaData  			//find SET/ENUM values
  			if($this->isEnumSetType($info['DbType']))
 -				$info['DbTypeValues'] = preg_split('/\s*,\s*|\s+/', preg_replace('/\'|"/', '', $match[1]));
 +				$info['DbTypeValues'] = preg_split("/[',]/S", $match[1], -1, PREG_SPLIT_NO_EMPTY);
  			//find column size, precision and scale
  			$pscale = array();
 @@ -212,9 +212,9 @@ class TMysqlMetaData extends TDbMetaData  		if($this->getServerVersion()<5.01)
  			return false;
  		if($schemaName!==null)
 -			$sql = "SHOW FULL TABLES FROM `{$schemaName}` LIKE ':table'";
 +			$sql = "SHOW FULL TABLES FROM `{$schemaName}` LIKE :table";
  		else
 -			$sql = "SHOW FULL TABLES LIKE ':table'";
 +			$sql = "SHOW FULL TABLES LIKE :table";
  		$command = $this->getDbConnection()->createCommand($sql);
  		$command->bindValue(':table', $tableName);
 @@ -246,8 +246,8 @@ class TMysqlMetaData extends TDbMetaData  			if($row['Key_name']==='PRIMARY')
  				$primary[] = $row['Column_name'];
  		}
 -        // MySQL version was increased to >=5.1.21 instead of 5.x -        // due to a MySQL bug (http://bugs.mysql.com/bug.php?id=19588) +        // MySQL version was increased to >=5.1.21 instead of 5.x
 +        // due to a MySQL bug (http://bugs.mysql.com/bug.php?id=19588)
  		if($this->getServerVersion() >= 5.121)
  			$foreign = $this->getForeignConstraints($schemaName,$tableName);
  		else
 @@ -353,4 +353,4 @@ EOD;  		return false;
  	}
  }
 - +
 diff --git a/framework/Data/Common/TDbCommandBuilder.php b/framework/Data/Common/TDbCommandBuilder.php index 155a62f8..0dc13e7e 100644 --- a/framework/Data/Common/TDbCommandBuilder.php +++ b/framework/Data/Common/TDbCommandBuilder.php @@ -157,16 +157,158 @@ class TDbCommandBuilder extends TComponent  	}
  	/**
 +	 *
 +	 * Different behavior depends on type of passed data
 +	 * string
 +	 * 	usage without modification
 +	 *
 +	 * null
 +	 * 	will be expanded to full list of quoted table column names (quoting depends on database)
 +	 *
 +	 * array
 +	 * - Column names will be quoted if used as key or value of array
 +	 * 	<code>
 +	 * 	array('col1', 'col2', 'col2')
 +	 * 	// SELECT `col1`, `col2`, `col3` FROM...
 +	 * 	</code>
 +	 *
 +	 * - Column aliasing
 +	 * <code>
 +	 * array('mycol1' => 'col1', 'mycol2' => 'COUNT(*)')
 +	 * // SELECT `col1` AS mycol1, COUNT(*) AS mycol2 FROM...
 +	 * </code>
 +	 *
 +	 * - NULL and scalar values (strings will be quoted depending on database)
 +	 * <code>
 +	 * array('col1' => 'my custom string', 'col2' => 1.0, 'col3' => 'NULL')
 +	 * // SELECT "my custom string" AS `col1`, 1.0 AS `col2`, NULL AS `col3` FROM...
 +	 * </code>
 +	 *
 +	 * - If the *-wildcard char is used as key or value, add the full list of quoted table column names
 +	 * <code>
 +	 * array('col1' => 'NULL', '*')
 +	 * // SELECT `col1`, `col2`, `col3`, NULL AS `col1` FROM...
 +	 * </code>
 +	 * @param mixed $value
 +	 * @return array of generated fields - use implode(', ', $selectfieldlist) to collapse field list for usage
 +	 * @since 3.1.7
 +	 * @todo add support for table aliasing
 +	 * @todo add support for quoting of column aliasing
 +	 */
 +	public function getSelectFieldList($data='*') {
 +		if(is_scalar($data)) {
 +			$tmp = explode(',', $data);
 +			$result = array();
 +			foreach($tmp as $v)
 +				$result[] = trim($v);
 +			return $result;
 +		}
 +
 +		$bHasWildcard = false;
 +		$result = array();
 +		if(is_array($data) || $data instanceof Traversable) {
 +			$columns = $this->getTableInfo()->getColumns();
 +			foreach($data as $key=>$value) {
 +				if($key==='*' || $value==='*') {
 +					$bHasWildcard = true;
 +					continue;
 +				}
 +
 +				if(strToUpper($key)==='NULL') {
 +					$result[] = 'NULL';
 +					continue;
 +				}
 +
 +				if(strpos($key, '(')!==false && strpos($key, ')')!==false) {
 +					$result[] = $key;
 +					continue;
 +				}
 +
 +				if(stripos($key, 'AS')!==false) {
 +					$result[] = $key;
 +					continue;
 +				}
 +
 +				if(stripos($value, 'AS')!==false) {
 +					$result[] = $value;
 +					continue;
 +				}
 +
 +				$v = isset($columns[$value]);
 +				$k = isset($columns[$key]);
 +				if(is_integer($key) && $v) {
 +					$key = $value;
 +					$k = $v;
 +				}
 +
 +				if(strToUpper($value)==='NULL') {
 +					if($k)
 +						$result[] = 'NULL AS ' . $columns[$key]->getColumnName();
 +					else
 +						$result[] = 'NULL' . (is_string($key) ? (' AS ' . (string)$key) : '');
 +					continue;
 +				}
 +
 +				if(strpos($value, '(')!==false && strpos($value, ')')!==false) {
 +					if($k)
 +						$result[] = $value . ' AS ' . $columns[$key]->getColumnName();
 +					else
 +						$result[] = $value . (is_string($key) ? (' AS ' . (string)$key) : '');
 +					continue;
 +				}
 +
 +				if($v && $key==$value) {
 +					$result[] = $columns[$value]->getColumnName();
 +					continue;
 +				}
 +
 +				if($k && $value==null) {
 +					$result[] = $columns[$key]->getColumnName();
 +					continue;
 +				}
 +
 +				if(is_string($key) && $v) {
 +					$result[] = $columns[$value]->getColumnName() . ' AS ' . $key;
 +					continue;
 +				}
 +
 +				if(is_numeric($value) && $k) {
 +					$result[] = $value . ' AS ' . $columns[$key]->getColumnName();
 +					continue;
 +				}
 +
 +				if(is_string($value) && $k) {
 +					$result[] = $this->getDbConnection()->quoteString($value) . ' AS ' . $columns[$key]->getColumnName();
 +					continue;
 +				}
 +
 +				if(!$v && !$k && is_integer($key)) {
 +					$result[] = is_numeric($value) ? $value : $this->getDbConnection()->quoteString((string)$value);
 +					continue;
 +				}
 +
 +				$result[] = (is_numeric($value) ? $value : $this->getDbConnection()->quoteString((string)$value)) . ' AS ' . $key;
 +			}
 +		}
 +
 +		if($data===null || count($result) == 0 || $bHasWildcard)
 +			$result = $result = array_merge($this->getTableInfo()->getColumnNames(), $result);
 +
 +		return $result;
 +	}
 +
 +	/**
  	 * Appends the $where condition to the string "SELECT * FROM tableName WHERE ".
  	 * The tableName is obtained from the {@link setTableInfo TableInfo} property.
  	 * @param string query condition
  	 * @param array condition parameters.
  	 * @return TDbCommand query command.
  	 */
 -	public function createFindCommand($where='1=1', $parameters=array(), $ordering=array(), $limit=-1, $offset=-1)
 +	public function createFindCommand($where='1=1', $parameters=array(), $ordering=array(), $limit=-1, $offset=-1, $select='*')
  	{
  		$table = $this->getTableInfo()->getTableFullName();
 -		$sql = "SELECT * FROM {$table}";
 +		$fields = implode(', ', $this -> getSelectFieldList($select));
 +		$sql = "SELECT {$fields} FROM {$table}";
  		if(!empty($where))
  			$sql .= " WHERE {$where}";
  		return $this->applyCriterias($sql, $parameters, $ordering, $limit, $offset);
 @@ -191,11 +333,7 @@ class TDbCommandBuilder extends TComponent  	 */
  	public function createCountCommand($where='1=1', $parameters=array(),$ordering=array(), $limit=-1, $offset=-1)
  	{
 -		$table = $this->getTableInfo()->getTableFullName();
 -		$sql = "SELECT COUNT(*) FROM {$table}";
 -		if(!empty($where))
 -			$sql .= " WHERE {$where}";
 -		return $this->applyCriterias($sql, $parameters, $ordering, $limit, $offset);
 +		return $this->createFindCommand($where, $parameters, $ordering, $limit, $offset, 'COUNT(*)');
  	}
  	/**
 @@ -368,4 +506,4 @@ class TDbCommandBuilder extends TComponent  	}
  }
 -?>
 +?>
\ No newline at end of file diff --git a/framework/Data/Common/TDbTableInfo.php b/framework/Data/Common/TDbTableInfo.php index e2aae3d0..455dbc33 100644 --- a/framework/Data/Common/TDbTableInfo.php +++ b/framework/Data/Common/TDbTableInfo.php @@ -27,7 +27,13 @@ class TDbTableInfo extends TComponent  	private $_columns;
 -	private $_lowercase;
 +	private $_lowercase; + +	/** +	 * @var null|array +	 * @since 3.1.7 +	 */
 +	private $_names = null;
  	/**
  	 * Sets the database table meta data information.
 @@ -118,11 +124,14 @@ class TDbTableInfo extends TComponent  	 * @return array table column names (identifier quoted)
  	 */
  	public function getColumnNames()
 -	{
 -		$names=array();
 -		foreach($this->getColumns() as $column)
 -			$names[] = $column->getColumnName();
 -		return $names;
 +	{ +		if($this->_names===null) +		{
 +			$this->_names=array();
 +			foreach($this->getColumns() as $column)
 +				$this->_names[] = $column->getColumnName(); +		}
 +		return $this->_names;
  	}
  	/**
 @@ -154,5 +163,4 @@ class TDbTableInfo extends TComponent  		}
  		return $this->_lowercase;
  	}
 -}
 - +}
\ No newline at end of file diff --git a/framework/Data/DataGateway/TDataGatewayCommand.php b/framework/Data/DataGateway/TDataGatewayCommand.php index 7425e6c4..e290f457 100644 --- a/framework/Data/DataGateway/TDataGatewayCommand.php +++ b/framework/Data/DataGateway/TDataGatewayCommand.php @@ -148,7 +148,8 @@ class TDataGatewayCommand extends TComponent  		$ordering = $criteria->getOrdersBy();
  		$limit = $criteria->getLimit();
  		$offset = $criteria->getOffset();
 -		$command = $this->getBuilder()->createFindCommand($where,$parameters,$ordering,$limit,$offset);
 +		$select = $criteria->getSelect();
 +		$command = $this->getBuilder()->createFindCommand($where,$parameters,$ordering,$limit,$offset,$select);
  		$this->onCreateCommand($command, $criteria);
  		return $command;
  	}
 @@ -232,7 +233,7 @@ class TDataGatewayCommand extends TComponent  			throw new TDbException('dbtablegateway_missing_pk_values',
  				$this->getTableInfo()->getTableFullName());
  		}
 -		if($count>1 && !is_array($values[0]))
 +		if($count>1 && (!isset($values[0]) || !is_array($values[0])))
  			$values = array($values);
  		if($count > 1 && count($values[0]) !== $count)
  		{
 diff --git a/framework/Data/DataGateway/TSqlCriteria.php b/framework/Data/DataGateway/TSqlCriteria.php index 4ebdeb48..14e37b35 100644 --- a/framework/Data/DataGateway/TSqlCriteria.php +++ b/framework/Data/DataGateway/TSqlCriteria.php @@ -31,6 +31,11 @@   */
  class TSqlCriteria extends TComponent
  {
 +	/**
 +	 * @var mixed
 +	 * @since 3.1.7
 +	 */
 +	private $_select='*';
  	private $_condition;
  	private $_parameters;
  	private $_ordersBy;
 @@ -56,6 +61,60 @@ class TSqlCriteria extends TComponent  	}
  	/**
 +	 * Gets the field list to be placed after the SELECT in the SQL. Default to '*'
 +	 * @return mixed
 +	 * @since 3.1.7
 +	 */
 +	public function getSelect()
 +	{
 +		return $this->_select;
 +	}
 +
 +	/**
 +	 * Sets the field list to be placed after the SELECT in the SQL.
 +	 *
 +	 * Different behavior depends on type of assigned value
 +	 * string
 +	 * 	usage without modification
 +	 *
 +	 * null
 +	 * 	will be expanded to full list of quoted table column names (quoting depends on database)
 +	 *
 +	 * array
 +	 * - Column names will be quoted if used as key or value of array
 +	 * 	<code>
 +	 * 	array('col1', 'col2', 'col2')
 +	 * 	// SELECT `col1`, `col2`, `col3` FROM...
 +	 * 	</code>
 +	 *
 +	 * - Column aliasing
 +	 * <code>
 +	 * array('mycol1' => 'col1', 'mycol2' => 'COUNT(*)')
 +	 * // SELECT `col1` AS mycol1, COUNT(*) AS mycol2 FROM...
 +	 * </code>
 +	 *
 +	 * - NULL and scalar values (strings will be quoted depending on database)
 +	 * <code>
 +	 * array('col1' => 'my custom string', 'col2' => 1.0, 'col3' => 'NULL')
 +	 * // SELECT "my custom string" AS `col1`, 1.0 AS `col2`, NULL AS `col3` FROM...
 +	 * </code>
 +	 *
 +	 * - If the *-wildcard char is used as key or value, add the full list of quoted table column names
 +	 * <code>
 +	 * array('col1' => 'NULL', '*')
 +	 * // SELECT `col1`, `col2`, `col3`, NULL AS `col1` FROM...
 +	 * </code>
 +	 *
 +	 * @param mixed
 +	 * @since 3.1.7
 +	 * @see TDbCommandBuilder::getSelectFieldList()
 +	 */
 +	public function setSelect($value)
 +	{
 +		$this->_select = $value;
 +	}
 +
 +	/**
  	 * @return string search conditions.
  	 */
  	public function getCondition()
 @@ -68,17 +127,17 @@ class TSqlCriteria extends TComponent  	 * @param string search conditions.
  	 */
  	public function setCondition($value)
 -	{		
 +	{
  		if(empty($value)) {
  			return;
  		}
 -		
 +
  		// supporting the following SELECT-syntax:
  		// [ORDER BY {col_name | expr | position}
  		//      [ASC | DESC], ...]
  		//    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
  		// See: http://dev.mysql.com/doc/refman/5.0/en/select.html
 -		
 +
  		if(preg_match('/ORDER\s+BY\s+(.*?)(?=LIMIT)|ORDER\s+BY\s+(.*?)$/i', $value, $matches) > 0) {
  			// condition contains ORDER BY
  			$value = str_replace($matches[0], '', $value);
 @@ -88,7 +147,7 @@ class TSqlCriteria extends TComponent  				$this->setOrdersBy($matches[2]);
  			}
  		}
 -		
 +
  		if(preg_match('/LIMIT\s+([\d\s,]+)/i', $value, $matches) > 0) {
  			// condition contains limit
  			$value = str_replace($matches[0], '', $value); // remove limit from query
 @@ -106,7 +165,7 @@ class TSqlCriteria extends TComponent  			$value = str_replace($matches[0], '', $value); // remove offset from query
  			$this->_offset = (int)$matches[1]; // set offset in criteria
  		}
 -		
 +
  		$this->_condition = trim($value);
  	}
 @@ -222,5 +281,4 @@ class TSqlCriteria extends TComponent  		return $str;
  	}
  }
 -
 -?>
 +?>
\ No newline at end of file diff --git a/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php b/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php index d85148eb..540a3acd 100644 --- a/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php +++ b/framework/Data/SqlMap/Configuration/TSqlMapCacheModel.php @@ -97,7 +97,7 @@ class TSqlMapCacheModel extends TComponent  	public function initialize($cache=null)
  	{
  		if($cache===null)
 -			$this->_cache= Prado::createComponent($this->getImplementationClass());
 +			$this->_cache= Prado::createComponent($this->getImplementationClass(), $this);
  		else
  			$this->_cache=$cache;
  	}
 diff --git a/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php b/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php index f6e0acd5..c49a4219 100644 --- a/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php +++ b/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php @@ -710,7 +710,7 @@ class TSqlMapXmlMappingConfiguration extends TSqlMapXmlConfigBuilder  			if(in_array(strtolower($name), $properties))
  				$cacheModel->{'set'.$name}((string)$value);
  		}
 -		$cache = Prado::createComponent($cacheModel->getImplementationClass());
 +		$cache = Prado::createComponent($cacheModel->getImplementationClass(), $cacheModel);
  		$this->setObjectPropFromNode($cache,$node,$properties);
  		foreach($node->xpath('property') as $propertyNode)
 diff --git a/framework/Data/SqlMap/DataMapper/TSqlMapCache.php b/framework/Data/SqlMap/DataMapper/TSqlMapCache.php index 05b72e08..5262bdf8 100644 --- a/framework/Data/SqlMap/DataMapper/TSqlMapCache.php +++ b/framework/Data/SqlMap/DataMapper/TSqlMapCache.php @@ -4,7 +4,7 @@   *
   * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System.Data.SqlMap
 @@ -25,16 +25,17 @@ abstract class TSqlMapCache implements ICache  	protected $_keyList;
  	protected $_cache;
  	protected $_cacheSize = 100;
 +	protected $_cacheModel = null;
  	/**
  	 * Create a new cache with limited cache size.
 -	 * @param integer maxium number of items to cache.
 +	 * @param TSqlMapCacheModel $cacheModel.
  	 */
 -	public function __construct($cacheSize=100)
 +	public function __construct($cacheModel=null)
  	{
  		$this->_cache = new TMap;
 -		$this->_cacheSize = intval($cacheSize);
  		$this->_keyList = new TList;
 +		$this->_cacheModel=$cacheModel;
  	}
  	/**
 @@ -173,20 +174,71 @@ class TSqlMapLruCache extends TSqlMapCache   */
  class TSqlMapApplicationCache implements ICache
  {
 +	protected $_cacheModel=null;
 +
 +	/**
 +	 * Create a new cache with limited cache size.
 +	 * @param TSqlMapCacheModel $cacheModel.
 +	 */
 +	public function __construct($cacheModel=null)
 +	{
 +		$this->_cacheModel=$cacheModel;
 +	}
 +
 +	/**
 +	 *
 +	 * @return string a KeyListID for the cache model.
 +	 */
 +	protected function getKeyListId()
 +	{
 +		$id='keyList';
 +		if ($this->_cacheModel instanceof TSqlMapCacheModel)
 +				$id.='_'.$this->_cacheModel->getId();
 +		return $id;
 +	}
 +	/**
 +	 * Retreive keylist from cache or create it if it doesn't exists
 +	 * @return TList
 +	 */
 +	protected function getKeyList()
 +	{
 +		if (($keyList=$this->getCache()->get($this->getKeyListId()))===false)
 +		{
 +			$keyList=new TList();
 +			$this->getCache()->set($this->getKeyListId(), $keyList);
 +		}
 +		return $keyList;
 +	}
 +
 +	protected function setKeyList($keyList)
 +	{
 +		$this->getCache()->set($this->getKeyListId(), $keyList);
 +	}
 +
  	/**
  	 * @param string item to be deleted.
  	 */
  	public function delete($key)
  	{
 +		$keyList=$this->getKeyList();
 +		$keyList->remove($key);
  		$this->getCache()->delete($key);
 +		$this->setKeyList($keyList);
  	}
  	/**
 -	 * Deletes all items in the cache.
 +	 * Deletes all items in the cache, only for data cached by sqlmap cachemodel
  	 */
  	public function flush()
  	{
 -		$this->getCache()->flush();
 +		$keyList=$this->getKeyList();
 +		$cache=$this->getCache();
 +		foreach ($keyList as $key)
 +		{
 +			$cache->delete($key);
 +		}
 +		// Remove the old keylist
 +		$cache->delete($this->getKeyListId());
  	}
  	/**
 @@ -195,6 +247,16 @@ class TSqlMapApplicationCache implements ICache  	public function get($key)
  	{
  		$result = $this->getCache()->get($key);
 +		if ($result === false)
 +		{
 +			// if the key has not been found in cache (e.g expired), remove from keylist
 +			$keyList=$this->getKeyList();
 +			if ($keyList->contains($key))
 +			{
 +				$keyList->remove($key);
 +				$this->setKeyList($keyList);
 +			}
 +		}
  		return $result === false ? null : $result;
  	}
 @@ -206,6 +268,12 @@ class TSqlMapApplicationCache implements ICache  	public function set($key, $value,$expire=0,$dependency=null)
  	{
  		$this->getCache()->set($key, $value, $expire,$dependency);
 +		$keyList=$this->getKeyList();
 +		if (!$keyList->contains($key))
 +		{
 +			$keyList->add($key);
 +			$this->setKeyList($keyList);
 +		}
  	}
  	/**
 diff --git a/framework/Data/SqlMap/TSqlMapConfig.php b/framework/Data/SqlMap/TSqlMapConfig.php index c57ab40e..c5f06ab8 100644 --- a/framework/Data/SqlMap/TSqlMapConfig.php +++ b/framework/Data/SqlMap/TSqlMapConfig.php @@ -53,6 +53,31 @@ class TSqlMapConfig extends TDataSourceConfig  	}
  	/**
 +	 * Create and configure the data mapper using sqlmap configuration file.
 +	 * Or if cache is enabled and manager already cached load from cache.
 +	 * If cache is enabled, the data mapper instance is cached.
 +	 *
 +	 * @return TSqlMapManager SqlMap manager instance
 +	 * @since 3.1.7
 +	 */
 +	public function getSqlMapManager() {
 +		Prado::using('System.Data.SqlMap.TSqlMapManager');
 +		if(($manager = $this->loadCachedSqlMapManager())===null)
 +		{
 +			$manager = new TSqlMapManager($this->getDbConnection());
 +			if(strlen($file=$this->getConfigFile()) > 0)
 +			{
 +				$manager->configureXml($file);
 +				$this->cacheSqlMapManager($manager);
 +			}
 +		}
 +		elseif($this->getConnectionID() !== '') {
 +			$manager->setDbConnection($this->getDbConnection());
 +		}
 +		return $manager;
 +	}
 +
 +	/**
  	 * Saves the current SqlMap manager to cache.
  	 * @return boolean true if SqlMap manager was cached, false otherwise.
  	 */
 @@ -87,6 +112,7 @@ class TSqlMapConfig extends TDataSourceConfig  					return $manager;
  			}
  		}
 +		return null;
  	}
  	/**
 @@ -134,26 +160,11 @@ class TSqlMapConfig extends TDataSourceConfig  	}
  	/**
 -	 * Configure the data mapper using sqlmap configuration file.
 -	 * If cache is enabled, the data mapper instance is cached.
  	 * @return TSqlMapGateway SqlMap gateway instance.
  	 */
  	protected function createSqlMapGateway()
  	{
 -		Prado::using('System.Data.SqlMap.TSqlMapManager');
 -		if(($manager = $this->loadCachedSqlMapManager())===null)
 -		{
 -			$manager = new TSqlMapManager($this->getDbConnection());
 -			if(strlen($file=$this->getConfigFile()) > 0)
 -			{
 -				$manager->configureXml($file);
 -				$this->cacheSqlMapManager($manager);
 -			}
 -		}
 -		else {
 -			$manager->setDbConnection($this->getDbConnection());
 -		}
 -		return $manager->getSqlmapGateway();
 +		return $this->getSqlMapManager()->getSqlmapGateway();
  	}
  	/**
 diff --git a/framework/Data/TDbConnection.php b/framework/Data/TDbConnection.php index 26d61883..4726083c 100644 --- a/framework/Data/TDbConnection.php +++ b/framework/Data/TDbConnection.php @@ -27,10 +27,10 @@ Prado::using('System.Data.TDbCommand');   * specifying {@link setConnectionString ConnectionString}, {@link setUsername Username}
   * and {@link setPassword Password}.
   *
 - * Since 3.1.2, the connection charset can be set (for MySQL and PostgreSQL databases only) 
 + * Since 3.1.2, the connection charset can be set (for MySQL and PostgreSQL databases only)
   * using the {@link setCharset Charset} property. The value of this property is database dependant.
 - * e.g. for mysql, you can use 'latin1' for cp1252 West European, 'utf8' for unicode, ... 
 - * 
 + * e.g. for mysql, you can use 'latin1' for cp1252 West European, 'utf8' for unicode, ...
 + *
   * The following example shows how to create a TDbConnection instance and establish
   * the actual connection:
   * <code>
 @@ -83,6 +83,12 @@ Prado::using('System.Data.TDbCommand');   */
  class TDbConnection extends TComponent
  {
 +	/**
 +	 *
 +	 * @since 3.1.7
 +	 */
 +	const DEFAULT_TRANSACTION_CLASS = 'System.Data.TDbTransaction';
 +
  	private $_dsn='';
  	private $_username='';
  	private $_password='';
 @@ -93,12 +99,18 @@ class TDbConnection extends TComponent  	private $_transaction;
  	/**
 +	 * @var string
 +	 * @since 3.1.7
 +	 */
 +	private $_transactionClass=self::DEFAULT_TRANSACTION_CLASS;
 +
 +	/**
  	 * Constructor.
  	 * Note, the DB connection is not established when this connection
  	 * instance is created. Set {@link setActive Active} property to true
  	 * to establish the connection.
  	 * Since 3.1.2, you can set the charset for MySql connection
 -	 * 
 +	 *
  	 * @param string The Data Source Name, or DSN, contains the information required to connect to the database.
  	 * @param string The user name for the DSN string.
  	 * @param string The password for the DSN string.
 @@ -168,7 +180,7 @@ class TDbConnection extends TComponent  			{
  				$this->_pdo=new PDO($this->getConnectionString(),$this->getUsername(),
  									$this->getPassword(),$this->_attributes); -				// This attribute is only useful for PDO::MySql driver.  +				// This attribute is only useful for PDO::MySql driver.
  				// Ignore the warning if a driver doesn't understand this.  				@$this->_pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
  				$this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 @@ -194,7 +206,7 @@ class TDbConnection extends TComponent  	/*
  	 * Set the database connection charset.
 -	 * Only MySql databases are supported for now. 
 +	 * Only MySql databases are supported for now.
  	 * @since 3.1.2
  	 */
  	protected function setConnectionCharset()
 @@ -204,7 +216,7 @@ class TDbConnection extends TComponent  		switch ($this->_pdo->getAttribute(PDO::ATTR_DRIVER_NAME))
  		{
  			case 'mysql':
 -				$stmt = $this->_pdo->prepare('SET CHARACTER SET ?');
 +				$stmt = $this->_pdo->prepare('SET NAMES ?');
  			break;
  			case 'pgsql':
  				$stmt = $this->_pdo->prepare('SET client_encoding TO ?');
 @@ -212,7 +224,7 @@ class TDbConnection extends TComponent  		}
  		$stmt->execute(array($this->_charset));
  	}
 -		
 +
  	/**
  	 * @return string The Data Source Name, or DSN, contains the information required to connect to the database.
  	 */
 @@ -269,7 +281,7 @@ class TDbConnection extends TComponent  	{
  		return $this->_charset;
  	}
 -	
 +
  	/**
  	 * @param string the charset used for database connection
  	 */
 @@ -278,7 +290,7 @@ class TDbConnection extends TComponent  		$this->_charset=$value;
  		$this->setConnectionCharset();
  	}
 -	
 +
  	/**
  	 * @return PDO the PDO instance, null if the connection is not established yet
  	 */
 @@ -324,13 +336,32 @@ class TDbConnection extends TComponent  		if($this->getActive())
  		{
  			$this->_pdo->beginTransaction();
 -			return $this->_transaction=new TDbTransaction($this);
 +			return $this->_transaction=Prado::createComponent($this->getTransactionClass(), $this);
  		}
  		else
  			throw new TDbException('dbconnection_connection_inactive');
  	}
  	/**
 +	 * @return string Transaction class name to be created by calling {@link TDbConnection::beginTransaction}. Defaults to 'System.Data.TDbTransaction'.
 +	 * @since 3.1.7
 +	 */
 +	public function getTransactionClass()
 +	{
 +		return $this->_transactionClass;
 +	}
 +
 +
 +	/**
 +	 * @param string Transaction class name to be created by calling {@link TDbConnection::beginTransaction}.
 +	 * @since 3.1.7
 +	 */
 +	public function setTransactionClass($value)
 +	{
 +		$this->_transactionClass = (string)$value;
 +	}
 +
 +	/**
  	 * Returns the ID of the last inserted row or sequence value.
  	 * @param string name of the sequence object (required by some DBMS)
  	 * @return string the row ID of the last row inserted, or the last value retrieved from the sequence object
 diff --git a/framework/Exceptions/messages/messages-fr.txt b/framework/Exceptions/messages/messages-fr.txt index 82507b1a..5dce3812 100644 --- a/framework/Exceptions/messages/messages-fr.txt +++ b/framework/Exceptions/messages/messages-fr.txt @@ -71,6 +71,7 @@ httpsession_autostart_unchangeable		= THttpSession.AutoStart ne peut pas être m  httpsession_gcprobability_unchangeable	= THttpSession.GCProbability ne peut pas être modifié après que la session ait démarré.  httpsession_gcprobability_invalid		= THttpSession.GCProbability doit être un entier compris entre 0 et 100.  httpsession_transid_unchangeable		= THttpSession.UseTransparentSessionID ne peut pas être modifié après que la session ait démarré. +httpsession_transid_cookieonly			= THttpSession.UseTransparentSessionID ne peut pas être utilisé quand THttpSession.CookieMode est fixé à "Only".  httpsession_maxlifetime_unchangeable	= THttpSession.Timeout ne peut pas être modifié après que la session ait démarré.  assetmanager_basepath_invalid			= TAssetManager.BasePath '{0}' est invalide. Vérifier qu'il est bien au format 'namespace' et qu'il pointe bien vers un répertoire accessible en écriture par le propriétaire du processus serveur Web diff --git a/framework/Exceptions/messages/messages-id.txt b/framework/Exceptions/messages/messages-id.txt index fb57a5ba..61699ddd 100644 --- a/framework/Exceptions/messages/messages-id.txt +++ b/framework/Exceptions/messages/messages-id.txt @@ -71,6 +71,7 @@ httpsession_autostart_unchangeable	= THttpSession.AutoStart tidak bisa diubah se  httpsession_gcprobability_unchangeable	= THttpSession.GCProbability tidak bisa diubah setelah sesi dimulai.
  httpsession_gcprobability_invalid	= THttpSession.GCProbability harus integer antara 0 dan 100.
  httpsession_transid_unchangeable	= THttpSession.UseTransparentSessionID tidak bisa diubah setelah sesi dimulai.
 +httpsession_transid_cookieonly			= THttpSession.UseTransparentSessionID cannot be set when THttpSession.CookieMode is set to Only.
  httpsession_maxlifetime_unchangeable	= THttpSession.Timeout tidak bisa diubah setelah sesi dimulai.
  assetmanager_basepath_invalid		= TAssetManager.BasePath '{0}' tidak benar. Pastikan ia dalam bentuk namespace dan mengarah ke direktori yang bisa ditulis oleh proses server Web.
 diff --git a/framework/Exceptions/messages/messages-zh.txt b/framework/Exceptions/messages/messages-zh.txt index d9a61083..1859aa92 100644 --- a/framework/Exceptions/messages/messages-zh.txt +++ b/framework/Exceptions/messages/messages-zh.txt @@ -76,6 +76,7 @@ httpsession_autostart_unchangeable		= THttpSession.AutoStartæ— æ³•è¢«ä¿®æ”¹ï¼Œå›  httpsession_gcprobability_unchangeable	= THttpSession.GCProbability无法被修改,因为sessionå·²ç»å¯åŠ¨äº†ã€‚  httpsession_gcprobability_invalid		= THttpSession.GCProbability必须是个0到100之间的整数。  httpsession_transid_unchangeable		= THttpSession.UseTransparentSessionID无法被修改,因为sessionå·²ç»å¯åŠ¨äº†ã€‚ +httpsession_transid_cookieonly			= THttpSession.UseTransparentSessionID cannot be set when THttpSession.CookieMode is set to Only.  httpsession_maxlifetime_unchangeable	= THttpSession.Timeout无法被修改,因为sessionå·²ç»å¯åŠ¨äº†ã€‚  assetmanager_basepath_invalid			= TAssetManager.BasePath所指路径“{0}â€éžæ³•。请确认它以命åç©ºé—´æ–¹å¼æŒ‡å®šï¼Œå¹¶ä¸”它所对应的文件目录å¯ä»¥è¢«WebæœåŠ¡å™¨è¿›ç¨‹å†™å…¥ã€‚ diff --git a/framework/Exceptions/messages/messages.txt b/framework/Exceptions/messages/messages.txt index 3bd6bbb1..402b3252 100644 --- a/framework/Exceptions/messages/messages.txt +++ b/framework/Exceptions/messages/messages.txt @@ -76,6 +76,7 @@ httpsession_autostart_unchangeable		= THttpSession.AutoStart cannot be modified  httpsession_gcprobability_unchangeable	= THttpSession.GCProbability cannot be modified after the session is started.  httpsession_gcprobability_invalid		= THttpSession.GCProbability must be an integer between 0 and 100.  httpsession_transid_unchangeable		= THttpSession.UseTransparentSessionID cannot be modified after the session is started. +httpsession_transid_cookieonly			= THttpSession.UseTransparentSessionID cannot be set when THttpSession.CookieMode is set to Only.  httpsession_maxlifetime_unchangeable	= THttpSession.Timeout cannot be modified after the session is started.  assetmanager_basepath_invalid			= TAssetManager.BasePath '{0}' is invalid. Make sure it is in namespace form and points to a directory writable by the Web server process. diff --git a/framework/TShellApplication.php b/framework/TShellApplication.php index 0d2cb826..e8560abf 100644 --- a/framework/TShellApplication.php +++ b/framework/TShellApplication.php @@ -4,7 +4,7 @@   *
   * @author Qiang Xue <qiang.xue@gmail.com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System
 @@ -35,6 +35,14 @@   */
  class TShellApplication extends TApplication
  {
 +
 +	/**
 +	 * Override parent implementation. TShellApplication doesn't need to start any service
 +	 */
 +	public function startService($serviceID)
 +	{
 +
 +	}
  	/**
  	 * Runs the application.
  	 * This method overrides the parent implementation by initializing
 diff --git a/framework/Util/TLogRouter.php b/framework/Util/TLogRouter.php index a8f42b56..c944e17d 100644 --- a/framework/Util/TLogRouter.php +++ b/framework/Util/TLogRouter.php @@ -635,6 +635,11 @@ class TEmailLogRoute extends TLogRoute   */
  class TBrowserLogRoute extends TLogRoute
  {
 +	/**
 +	 * @var string css class for indentifying the table structure in the dom tree
 +	 */
 +	private $_cssClass=null;
 +	
  	public function processLogs($logs)
  	{
  		if(empty($logs) || $this->getApplication()->getMode()==='Performance') return;
 @@ -659,10 +664,43 @@ class TBrowserLogRoute extends TLogRoute  		}
  		$response->write($this->renderFooter());
  	}
 +	
 +	/**
 +	 * @param string the css class of the control
 +	 */
 +	public function setCssClass($value)
 +	{
 +		$this->_cssClass = TPropertyValue::ensureString($value);
 +	}
 +
 +	/**
 +	 * @return string the css class of the control
 +	 */
 +	public function getCssClass()
 +	{
 +		return TPropertyValue::ensureString($this->_cssClass);
 +	}
  	protected function renderHeader()
  	{
 -		$string = <<<EOD
 +		$string = '';
 +		if($className=$this->getCssClass())
 +		{
 +			$string = <<<EOD
 +<table class="$className">
 +	<tr class="header">
 +		<th colspan="5">
 +			Application Log
 +		</th>
 +	</tr><tr class="description">
 +	    <th> </th>
 +		<th>Category</th><th>Message</th><th>Time Spent (s)</th><th>Cumulated Time Spent (s)</th>
 +	</tr>
 +EOD;
 +		}
 +		else
 +		{
 +			$string = <<<EOD
  <table cellspacing="0" cellpadding="2" border="0" width="100%" style="table-layout:auto">
  	<tr>
  		<th style="background-color: black; color:white;" colspan="5">
 @@ -673,18 +711,36 @@ class TBrowserLogRoute extends TLogRoute  		<th style="width: auto">Category</th><th style="width: auto">Message</th><th style="width: 120px">Time Spent (s)</th><th style="width: 150px">Cumulated Time Spent (s)</th>
  	</tr>
  EOD;
 +		}
  		return $string;
  	}
  	protected function renderMessage($log, $info)
  	{
 -		$bgcolor = $info['even'] ? "#fff" : "#eee";
 +		$string = '';
  		$total = sprintf('%0.6f', $info['total']);
  		$delta = sprintf('%0.6f', $info['delta']);
 -		$color = $this->getColorLevel($log[1]);
  		$msg = preg_replace('/\(line[^\)]+\)$/','',$log[0]); //remove line number info
  		$msg = THttpUtility::htmlEncode($msg);
 -		$string = <<<EOD
 +		if($this->getCssClass())
 +		{
 +			$colorCssClass = $log[1];
 +			$messageCssClass = $info['even'] ? 'even' : 'odd';
 +			$string = <<<EOD
 +	<tr class="message level$colorCssClass $messageCssClass">
 +		<td class="code"> </td>
 +		<td class="category">{$log[2]}</td>
 +		<td class="message">{$msg}</td>
 +		<td class="time">{$delta}</td>
 +		<td class="cumulatedtime">{$total}</td>
 +	</tr>
 +EOD;
 +		}
 +		else
 +		{
 +			$bgcolor = $info['even'] ? "#fff" : "#eee";
 +			$color = $this->getColorLevel($log[1]);
 +			$string = <<<EOD
  	<tr style="background-color: {$bgcolor}; color:#000">
  		<td style="border:1px solid silver;background-color: $color;"> </td>
  		<td>{$log[2]}</td>
 @@ -693,6 +749,7 @@ EOD;  		<td style="text-align:center">{$total}</td>
  	</tr>
  EOD;
 +		}
  		return $string;
  	}
 @@ -713,13 +770,25 @@ EOD;  	protected function renderFooter()
  	{
 -		$string = "<tr><td colspan=\"5\" style=\"text-align:center; background-color:black; border-top: 1px solid #ccc; padding:0.2em;\">";
 -		foreach(self::$_levelValues as $name => $level)
 +		$string = '';
 +		if($this->getCssClass())
  		{
 -			$string .= "<span style=\"color:white; border:1px solid white; background-color:".$this->getColorLevel($level);
 -			$string .= ";margin: 0.5em; padding:0.01em;\">".strtoupper($name)."</span>";
 +			$string .= '<tr class="footer"><td colspan="5">';
 +			foreach(self::$_levelValues as $name => $level)
 +			{
 +				$string .= '<span class="level'.$level.'">'.strtoupper($name)."</span>";
 +			}
 +		}
 +		else
 +		{
 +			$string .= "<tr><td colspan=\"5\" style=\"text-align:center; background-color:black; border-top: 1px solid #ccc; padding:0.2em;\">";
 +			foreach(self::$_levelValues as $name => $level)
 +			{
 +				$string .= "<span style=\"color:white; border:1px solid white; background-color:".$this->getColorLevel($level);
 +				$string .= ";margin: 0.5em; padding:0.01em;\">".strtoupper($name)."</span>";
 +			}
  		}
 -		$string .= "</td></tr></table>";
 +		$string .= '</td></tr></table>';
  		return $string;
  	}
  }
 diff --git a/framework/Web/Javascripts/source/prado/activecontrols/activedatepicker.js b/framework/Web/Javascripts/source/prado/activecontrols/activedatepicker.js index 3aacda21..e96b63ec 100755 --- a/framework/Web/Javascripts/source/prado/activecontrols/activedatepicker.js +++ b/framework/Web/Javascripts/source/prado/activecontrols/activedatepicker.js @@ -46,9 +46,9 @@ Prado.WebUI.TActiveDatePicker = Class.extend(Prado.WebUI.TDatePicker,  			var day = Prado.WebUI.TDatePicker.getDayListControl(this.control);  			var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control);  			var year = Prado.WebUI.TDatePicker.getYearListControl(this.control); -			Event.observe (day, "change", this.onDateChanged.bindEvent(this)); -			Event.observe (month, "change", this.onDateChanged.bindEvent(this)); -			Event.observe (year, "change", this.onDateChanged.bindEvent(this)); +			if (day) Event.observe (day, "change", this.onDateChanged.bindEvent(this)); +			if (month) Event.observe (month, "change", this.onDateChanged.bindEvent(this)); +			if (year) Event.observe (year, "change", this.onDateChanged.bindEvent(this));  		} @@ -66,9 +66,12 @@ Prado.WebUI.TActiveDatePicker = Class.extend(Prado.WebUI.TDatePicker,  		 }   		 else  		 { -		 	var day = Prado.WebUI.TDatePicker.getDayListControl(this.control).selectedIndex+1; -			var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control).selectedIndex; -			var year = Prado.WebUI.TDatePicker.getYearListControl(this.control).value; +		 	var day = Prado.WebUI.TDatePicker.getDayListControl(this.control); +			if (day) day=day.selectedIndex+1; +			var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control); +			if (month) month=month.selectedIndex; +			var year = Prado.WebUI.TDatePicker.getYearListControl(this.control); +			if (year) year=year.value;  			date=new Date(year, month, day, 0,0,0).SimpleFormat(this.Format, this);  		}  		if (typeof(this.options.OnDateChanged) == "function") this.options.OnDateChanged(this, date); diff --git a/framework/Web/Javascripts/source/prado/activefileupload/activefileupload.js b/framework/Web/Javascripts/source/prado/activefileupload/activefileupload.js index f42a0673..de633c77 100755 --- a/framework/Web/Javascripts/source/prado/activefileupload/activefileupload.js +++ b/framework/Web/Javascripts/source/prado/activefileupload/activefileupload.js @@ -46,20 +46,41 @@ Prado.WebUI.TActiveFileUpload = Base.extend(  	},  	finishUpload : function(options){ + +		if (this.options.targetID == options.targetID) +         		{ +				this.finishoptions = options; +         			var e = this; +         			var callback = +         			{ +         				'CallbackParameter' : options || '', +         				'onSuccess' : function() { e.finishCallBack(true); }, +					'onFailure' : function() { e.finishCallBack(false); } +         			}; + +         			Object.extend(callback, this.options); + +         			request = new Prado.CallbackRequest(this.options.EventTarget, callback); +         			request.dispatch(); +         		} +		else +			this.finishCallBack(true); + +	}, + +	finishCallBack : function(success){  		// hide the display indicator.  		this.flag.value = '';  		this.indicator.style.display = 'none'; -		if (this.options.targetID == options.targetID){ -			// show the complete indicator. -			if (options.errorCode == 0){ -				this.complete.style.display = ''; -				this.input.value = ''; -			} else { -				this.error.style.display = ''; -			} -			Prado.Callback(this.options.EventTarget, options, null, this.options); -		} +       		// show the complete indicator. +       		if ((this.finishoptions.errorCode == 0) && (success)) { +       			this.complete.style.display = ''; +       			this.input.value = ''; +       		} else { +       			this.error.style.display = ''; +       		}  	} +  },  {  // class methods diff --git a/framework/Web/Javascripts/source/prado/validator/validation3.js b/framework/Web/Javascripts/source/prado/validator/validation3.js index ed9493be..b1bf1a03 100644 --- a/framework/Web/Javascripts/source/prado/validator/validation3.js +++ b/framework/Web/Javascripts/source/prado/validator/validation3.js @@ -795,7 +795,7 @@ Prado.WebUI.TBaseValidator.prototype =  		 * Wether the validator is enabled (default true)
  		 * @var {boolean} enabled
  		 */
 -		this.enabled = true;
 +		this.enabled = options.Enabled;
  		/**
  		 * Visibility state of validator(default false)
  		 * @var {boolean} visible
 @@ -837,6 +837,7 @@ Prado.WebUI.TBaseValidator.prototype =  		 * @var {element} message
  		 */
  		this.message = $(options.ID);
 +
  		Prado.Registry.set(options.ID, this);
  		if(this.control && this.message)
  		{
 @@ -1706,7 +1707,7 @@ Prado.WebUI.TRegularExpressionValidator = Class.extend(Prado.WebUI.TBaseValidato  		if (value.length <= 0)
  	    	return true;
 -		var rx = new RegExp(this.options.ValidationExpression,this.options.PatternModifiers);
 +		var rx = new RegExp('^'+this.options.ValidationExpression+'$',this.options.PatternModifiers);
  		var matches = rx.exec(value);
  		return (matches != null && value == matches[0]);
  	}
 diff --git a/framework/Web/THttpRequest.php b/framework/Web/THttpRequest.php index 7100a4c5..c3926d08 100644 --- a/framework/Web/THttpRequest.php +++ b/framework/Web/THttpRequest.php @@ -105,7 +105,7 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  	/**  	 * @var boolean whether the session ID should be kept in cookie only  	 */ -	private $_cookieOnly=false; +	private $_cookieOnly=null;  	private $_urlFormat=THttpRequestUrlFormat::Get;  	private $_services;  	private $_requestResolved=false; @@ -172,8 +172,6 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  			$_SERVER['HTTP_USER_AGENT']='';  		} -		$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies'); -  		// Info about server variables:  		// PHP_SELF contains real URI (w/ path info, w/o query string)  		// SCRIPT_NAME is the real URI for the requested script (w/o path info and query string) @@ -568,6 +566,8 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  	 */  	public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)  	{ +		if ($this->_cookieOnly===null) +				$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');  		$url=$this->_urlManager->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);  		if(defined('SID') && SID != '' && !$this->_cookieOnly)  			return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&':'&')) . SID; diff --git a/framework/Web/THttpResponse.php b/framework/Web/THttpResponse.php index 3222f22f..c15f2836 100644 --- a/framework/Web/THttpResponse.php +++ b/framework/Web/THttpResponse.php @@ -66,6 +66,9 @@ Prado::using('System.Web.THttpResponseAdapter');   */
  class THttpResponse extends TModule implements ITextWriter
  {
 +	const DEFAULT_CONTENTTYPE	= 'text/html';
 +	const DEFAULT_CHARSET		= 'UTF-8';
 +
  	/**
  	 * @var The differents defined status code by RFC 2616 {@link http://www.faqs.org/rfcs/rfc2616}
  	 */
 @@ -106,7 +109,7 @@ class THttpResponse extends TModule implements ITextWriter  	 */
  	private $_contentType=null;
  	/**
 -	 * @var string character set, e.g. UTF-8
 +	 * @var string|boolean character set, e.g. UTF-8 or false if no character set should be send to client
  	 */
  	private $_charset='';
  	/**
 @@ -212,7 +215,7 @@ class THttpResponse extends TModule implements ITextWriter  	}
  	/**
 -	 * @return string output charset.
 +	 * @return string|boolean output charset.
  	 */
  	public function getCharset()
  	{
 @@ -220,11 +223,11 @@ class THttpResponse extends TModule implements ITextWriter  	}
  	/**
 -	 * @param string output charset.
 +	 * @param string|boolean output charset.
  	 */
  	public function setCharset($charset)
  	{
 -		$this->_charset = $charset;
 +		$this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
  	}
  	/**
 @@ -465,20 +468,22 @@ class THttpResponse extends TModule implements ITextWriter  	}
  	/**
 -	 * Sends content type header if charset is not empty.
 +	 * Sends content type header with optional charset.
  	 */
  	protected function sendContentTypeHeader()
  	{
 +		$contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
  		$charset=$this->getCharset();
 +		if($charset === false) {
 +			$this->appendHeader('Content-Type: '.$contentType);
 +			return;
 +		}
 +
  		if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
  			$charset=$globalization->getCharset();
 -		if($charset!=='')
 -		{
 -			$contentType=$this->_contentType===null?'text/html':$this->_contentType;
 -			$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
 -		}
 -		else if($this->_contentType!==null)
 -			$this->appendHeader('Content-Type: '.$this->_contentType.';charset=UTF-8');
 +
 +		if($charset==='') $charset = self::DEFAULT_CHARSET;
 +		$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
  	}
  	/**
 diff --git a/framework/Web/THttpSession.php b/framework/Web/THttpSession.php index 96d70704..e9f815e5 100644 --- a/framework/Web/THttpSession.php +++ b/framework/Web/THttpSession.php @@ -4,7 +4,7 @@   *
   * @author Qiang Xue <qiang.xue@gmail.com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System.Web
 @@ -115,7 +115,7 @@ class THttpSession extends TApplicationComponent implements IteratorAggregate,Ar  		if($this->_autoStart)
  			$this->open();
  		$this->_initialized=true;
 -		$this->getApplication()->setSession($this); +		$this->getApplication()->setSession($this);
  		register_shutdown_function(array($this, "close"));
  	}
 @@ -296,6 +296,7 @@ class THttpSession extends TApplicationComponent implements IteratorAggregate,Ar  			{
  				ini_set('session.use_cookies','1');
  				ini_set('session.use_only_cookies','1');
 +				ini_set('session.use_trans_sid', 0);
  			}
  		}
  	}
 @@ -366,7 +367,12 @@ class THttpSession extends TApplicationComponent implements IteratorAggregate,Ar  		if($this->_started)
  			throw new TInvalidOperationException('httpsession_transid_unchangeable');
  		else
 -			ini_set('session.use_trans_sid',TPropertyValue::ensureBoolean($value)?'1':'0');
 +		{
 +			$value=TPropertyValue::ensureBoolean($value);
 +			if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
 +					throw new TInvalidOperationException('httpsession_transid_cookieonly');
 +			ini_set('session.use_trans_sid',$value?'1':'0');
 +		}
  	}
  	/**
 diff --git a/framework/Web/UI/ActiveControls/TDropContainer.php b/framework/Web/UI/ActiveControls/TDropContainer.php index 8f7792f3..9c2e1dd5 100755 --- a/framework/Web/UI/ActiveControls/TDropContainer.php +++ b/framework/Web/UI/ActiveControls/TDropContainer.php @@ -62,6 +62,13 @@ class TDropContainer extends TPanel implements IActiveControl, ICallbackEventHan  		return $this->getAdapter()->getBaseActiveControl();  	} +	/** +	 * @return TCallbackClientSide client side request options. +	 */ +	public function getClientSide() +	{ +		return $this->getAdapter()->getBaseActiveControl()->getClientSide(); +	}  	/**  	 * Gets the Css class name that this container can accept. diff --git a/framework/Web/UI/WebControls/TBaseValidator.php b/framework/Web/UI/WebControls/TBaseValidator.php index 6daae4d0..0c71f46d 100644 --- a/framework/Web/UI/WebControls/TBaseValidator.php +++ b/framework/Web/UI/WebControls/TBaseValidator.php @@ -167,6 +167,7 @@ abstract class TBaseValidator extends TLabel implements IValidator  		$options['ControlCssClass'] = $this->getControlCssClass();
  		$options['ControlType'] = $this->getClientControlClass($control);
 +		$options['Enabled'] = $this->getEnabled(true);
  		//get date format from date picker target control
  		if($control instanceof TDatePicker)
 @@ -241,7 +242,7 @@ abstract class TBaseValidator extends TLabel implements IValidator  			$scripts->registerPradoScript('validator');
  			$scripts->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");
  		}
 -		if($this->getEnableClientScript() & $this->getEnabled(true))
 +		if($this->getEnableClientScript())
  			$this->registerClientScriptValidator();
  	}
 diff --git a/framework/Web/UI/WebControls/TBoundColumn.php b/framework/Web/UI/WebControls/TBoundColumn.php index 0f48d6e7..fdcde9b2 100644 --- a/framework/Web/UI/WebControls/TBoundColumn.php +++ b/framework/Web/UI/WebControls/TBoundColumn.php @@ -4,7 +4,7 @@   *
   * @author Qiang Xue <qiang.xue@gmail.com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System.Web.UI.WebControls
 diff --git a/framework/Web/UI/WebControls/TCheckBoxList.php b/framework/Web/UI/WebControls/TCheckBoxList.php index 742dd18b..c7c9fc98 100644 --- a/framework/Web/UI/WebControls/TCheckBoxList.php +++ b/framework/Web/UI/WebControls/TCheckBoxList.php @@ -4,7 +4,7 @@   *
   * @author Qiang Xue <qiang.xue@gmail.com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System.Web.UI.WebControls
 @@ -53,7 +53,7 @@ class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingCont  	private $_isEnabled;
  	private $_changedEventRaised=false;
  	private $_dataChanged=false;
 -	private $_isValid=true; +	private $_isValid=true;
  	/**
  	 * Constructor.
 @@ -254,6 +254,31 @@ class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingCont  	{
  		return false;
  	}
 +	
 +	/**
 +	 * @param boolean whether the control is to be enabled.
 +	 */
 +	public function setEnabled($value)
 +	{
 +		parent::setEnabled($value);
 +		$value = !TPropertyValue::ensureBoolean($value);
 +		// if this is an active control, 
 +		// and it's a callback, 
 +		// and we can update clientside,
 +		// then update the 'disabled' attribute of the items.
 +		if(($this instanceof IActiveControl) &&
 +				$this->getPage()->getIsCallBack() &&
 +				$this->getActiveControl()->canUpdateClientSide())
 +		{
 +			$items = $this->getItems();
 +			$cs = $this->getPage()->getCallbackClient();
 +			$baseClientID = $this->getClientID().'_c';
 +			foreach($items as $index=>$item)
 +			{
 +				$cs->setAttribute($baseClientID.$index, 'disabled', $value);
 +			}
 +		}
 +	}
  	/**
  	 * Returns a style used for rendering items.
 @@ -359,16 +384,16 @@ class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingCont  			$page->registerRequiresPostData($this->_repeatedControl);
  		}
  	}
 - -	/** -	 * Wether the list should be rendered inside a span or not -	 *  -	 *@return boolean true if we need a span -	 */ -	protected function getSpanNeeded () -	{ -		return $this->getRepeatLayout()===TRepeatLayout::Raw; -	} +
 +	/**
 +	 * Wether the list should be rendered inside a span or not
 +	 * 
 +	 *@return boolean true if we need a span
 +	 */
 +	protected function getSpanNeeded ()
 +	{
 +		return $this->getRepeatLayout()===TRepeatLayout::Raw;
 +	}
  	/**
  	 * Renders the checkbox list control.
 @@ -379,11 +404,11 @@ class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingCont  	{
  		if($this->getItemCount()>0)
  		{
 -			if ($needSpan=$this->getSpanNeeded()) -			{ -				$writer->addAttribute('id', $this->getClientId()); -				$writer->renderBeginTag('span'); -			} +			if ($needSpan=$this->getSpanNeeded())
 +			{
 +				$writer->addAttribute('id', $this->getClientId());
 +				$writer->renderBeginTag('span');
 +			}
  			$this->_isEnabled=$this->getEnabled(true);
  			$repeatInfo=$this->getRepeatInfo();
  			$accessKey=$this->getAccessKey();
 @@ -395,8 +420,8 @@ class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingCont  			$this->setTabIndex(0);
  			$repeatInfo->renderRepeater($writer,$this);
  			$this->setAccessKey($accessKey);
 -			$this->setTabIndex($tabIndex); -			if ($needSpan) +			$this->setTabIndex($tabIndex);
 +			if ($needSpan)
  				$writer->renderEndTag();
  		}
  		//checkbox skipped the client control script in addAttributesToRender
 @@ -429,23 +454,23 @@ class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingCont  		return $this->getSelectedValue();
  	}
 -	/** -	 * Returns true if this control validated successfully.  -	 * Defaults to true. -	 * @return bool wether this control validated successfully. -	 */ -	public function getIsValid() -	{ -	    return $this->_isValid; -	} -	/** -	 * @param bool wether this control is valid. -	 */ -	public function setIsValid($value) -	{ -	    $this->_isValid=TPropertyValue::ensureBoolean($value); -	} - +	/**
 +	 * Returns true if this control validated successfully. 
 +	 * Defaults to true.
 +	 * @return bool wether this control validated successfully.
 +	 */
 +	public function getIsValid()
 +	{
 +	    return $this->_isValid;
 +	}
 +	/**
 +	 * @param bool wether this control is valid.
 +	 */
 +	public function setIsValid($value)
 +	{
 +	    $this->_isValid=TPropertyValue::ensureBoolean($value);
 +	}
 +
  	/**
  	 * Gets the name of the javascript class responsible for performing postback for this control.
  	 * This method overrides the parent implementation.
 @@ -468,7 +493,7 @@ class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingCont  		$options['ListName'] = $this->getUniqueID();
  		$options['ItemCount'] = $this->getItemCount();
  		return $options;
 -	} +	}
  }
 diff --git a/framework/Web/UI/WebControls/TDataGridColumn.php b/framework/Web/UI/WebControls/TDataGridColumn.php index 577c0068..ed53dc88 100644 --- a/framework/Web/UI/WebControls/TDataGridColumn.php +++ b/framework/Web/UI/WebControls/TDataGridColumn.php @@ -4,7 +4,7 @@   *
   * @author Qiang Xue <qiang.xue@gmail.com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System.Web.UI.WebControls
 @@ -418,6 +418,7 @@ abstract class TDataGridColumn extends TApplicationComponent  		if(($classPath=$this->getHeaderRenderer())!=='')
  		{
  			$control=Prado::createComponent($classPath);
 +			$cell->getControls()->add($control);
  			if($control instanceof IDataRenderer)
  			{
  				if($control instanceof IItemDataRenderer)
 @@ -428,7 +429,6 @@ abstract class TDataGridColumn extends TApplicationComponent  				}
  				$control->setData($text);
  			}
 -			$cell->getControls()->add($control);
  		}
  		else if($this->getAllowSorting())
  		{
 @@ -489,6 +489,7 @@ abstract class TDataGridColumn extends TApplicationComponent  		if(($classPath=$this->getFooterRenderer())!=='')
  		{
  			$control=Prado::createComponent($classPath);
 +			$cell->getControls()->add($control);
  			if($control instanceof IDataRenderer)
  			{
  				if($control instanceof IItemDataRenderer)
 @@ -499,7 +500,6 @@ abstract class TDataGridColumn extends TApplicationComponent  				}
  				$control->setData($text);
  			}
 -			$cell->getControls()->add($control);
  		}
  		else if($text!=='')
  			$cell->setText($text);
 diff --git a/framework/Web/UI/WebControls/TJavascriptLogger.php b/framework/Web/UI/WebControls/TJavascriptLogger.php index 6d49f801..778b6728 100644 --- a/framework/Web/UI/WebControls/TJavascriptLogger.php +++ b/framework/Web/UI/WebControls/TJavascriptLogger.php @@ -4,7 +4,7 @@   *
   * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System.Web.UI.WebControls
 @@ -23,7 +23,7 @@   *
   * To see the logger and console, press ALT-D (or CTRL-D on OS X).
   * More information on the logger can be found at
 - * http://gleepglop.com/javascripts/logger/
 + * http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/
   *
   * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
   * @version $Id$
 @@ -84,7 +84,7 @@ class TJavascriptLogger extends TWebControl  	public function renderContents($writer)
  	{
  		$code = strtoupper($this->getToggleKey());
 -		$info = '(<a href="http://gleepglop.com/javascripts/logger/" target="_blank">more info</a>).';
 +		$info = '(<a href="http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/" target="_blank">more info</a>).';
  		$link = '<a href="javascript:if(logConsole)logConsole.toggle()">toggle the javascript log console.</a>';
  		$usage = 'Press ALT-'.$code.' (Or CTRL-'.$code.' on OS X) to';
  		$writer->write("{$usage} {$link} {$info}");
 diff --git a/framework/Web/UI/WebControls/TRegularExpressionValidator.php b/framework/Web/UI/WebControls/TRegularExpressionValidator.php index be861e45..6855c6de 100644 --- a/framework/Web/UI/WebControls/TRegularExpressionValidator.php +++ b/framework/Web/UI/WebControls/TRegularExpressionValidator.php @@ -4,7 +4,7 @@   *
   * @author Qiang Xue <qiang.xue@gmail.com>
   * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2008 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id$
   * @package System.Web.UI.WebControls
 @@ -86,7 +86,7 @@ class TRegularExpressionValidator extends TBaseValidator  	{
  		if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
  			return true;
 -		if(($expression=$this->getRegularExpression())!=='')
 +		if(($expression=addcslashes($this->getRegularExpression(),"/"))!=='')
  		{
  			$mods = $this->getPatternModifiers();
  			return preg_match("/^$expression\$/{$mods}",$value);
 diff --git a/framework/Web/UI/WebControls/TTabPanel.php b/framework/Web/UI/WebControls/TTabPanel.php index 961d0797..5deced79 100644 --- a/framework/Web/UI/WebControls/TTabPanel.php +++ b/framework/Web/UI/WebControls/TTabPanel.php @@ -413,6 +413,7 @@ class TTabPanel extends TWebControl implements IPostBackDataHandler  		$cs->registerEndScript("prado:$id", $code);
  		$cs->registerHiddenField($id.'_1',$this->getActiveViewIndex());
  		$page->registerRequiresPostData($this);
 +		$page->registerRequiresPostData($id."_1");
  	}
  	/**
 diff --git a/framework/Web/UI/WebControls/TTextBox.php b/framework/Web/UI/WebControls/TTextBox.php index 4e6a66e9..8ab548a3 100644 --- a/framework/Web/UI/WebControls/TTextBox.php +++ b/framework/Web/UI/WebControls/TTextBox.php @@ -245,7 +245,7 @@ class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable  	}
  	/** -	 * Returns true if this control validated successfully.  +	 * Returns true if this control validated successfully.  	 * Defaults to true.  	 * @return bool wether this control validated successfully.  	 */ @@ -299,6 +299,18 @@ class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable  	}
  	/**
 +	 * Renders an additional line-break after the opening tag when it
 +	 * is in MultiLine text mode.
 +	 * @param THtmlWriter the writer used for the rendering purpose^M
 +	 */
 +	public function renderBeginTag($writer)
 +	{
 +		parent::renderBeginTag($writer);
 +		if($this->getTextMode()==='MultiLine')
 +			$writer->write("\n");
 +	}
 +
 +	/**
  	 * @return TTextBoxAutoCompleteType the AutoComplete type of the textbox
  	 */
  	public function getAutoCompleteType()
 diff --git a/framework/Web/UI/WebControls/TValidationSummary.php b/framework/Web/UI/WebControls/TValidationSummary.php index ab066f78..4ed2eebe 100644 --- a/framework/Web/UI/WebControls/TValidationSummary.php +++ b/framework/Web/UI/WebControls/TValidationSummary.php @@ -149,6 +149,22 @@ class TValidationSummary extends TWebControl  	}
  	/**
 +	 * @return boolean whether scroll summary into viewport or not. Defaults to true.
 +	 */
 +	public function getScrollToSummary()
 +	{
 +		return $this->getViewState('ScrollToSummary',true);
 +	}
 +
 +	/**
 +	 * @param boolean whether scroll summary into viewport or not.
 +	 */
 +	public function setScrollToSummary($value)
 +	{
 +		$this->setViewState('ScrollToSummary',TPropertyValue::ensureBoolean($value),true);
 +	}
 +
 +	/**
  	 * @return boolean whether the validation summary should be anchored. Defaults to false.
  	 */
  	public function getShowAnchor()
 @@ -254,6 +270,7 @@ class TValidationSummary extends TWebControl  		if(!$this->getShowSummary())
  			$options['ShowSummary']=false;
 +		$options['ScrollToSummary']=$this->getScrollToSummary();
  		$options['HeaderText']=$this->getHeaderText();
  		$options['DisplayMode']=$this->getDisplayMode();
 diff --git a/framework/pradolite.php b/framework/pradolite.php new file mode 100644 index 00000000..6d5b13fd --- /dev/null +++ b/framework/pradolite.php @@ -0,0 +1,9489 @@ +<?php
 +/**
 + * File Name: pradolite.php
 + * Last Update: 2009/05/29 18:09:00
 + * Generated By: buildscripts/phpbuilder/build.php
 + *
 + * This file is used in lieu of prado.php to boost PRADO application performance.
 + * It is generated by expanding prado.php with included files.
 + * Comments and trace statements are stripped off.
 + *
 + * Do not modify this file manually.
 + */
 + +if(!defined('PRADO_DIR')) +	define('PRADO_DIR',dirname(__FILE__)); +if(!defined('PRADO_CHMOD')) +	define('PRADO_CHMOD',0777); +class PradoBase +{ +	const CLASS_FILE_EXT='.php'; +	private static $_aliases=array('System'=>PRADO_DIR); +	private static $_usings=array(); +	private static $_application=null; +	private static $_logger=null; +	public static function getVersion() +	{ +		return '3.1.6-dev'; +	} +	public static function initErrorHandlers() +	{ +		set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting()); +		set_exception_handler(array('PradoBase','exceptionHandler')); +	} +	public static function autoload($className) +	{ +		include_once($className.self::CLASS_FILE_EXT); +		if(!class_exists($className,false) && !interface_exists($className,false)) +			self::fatalError("Class file for '$className' cannot be found."); +	} +	public static function poweredByPrado($logoType=0) +	{ +		$logoName=$logoType==1?'powered2':'powered'; +		if(self::$_application!==null) +		{ +			$am=self::$_application->getAssetManager(); +			$url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif')); +		} +		else +			$url='http://www.pradosoft.com/images/'.$logoName.'.gif'; +		return '<a title="Powered by PRADO" href="http://www.pradosoft.com/" target="_blank"><img src="'.$url.'" style="border-width:0px;" alt="Powered by PRADO" /></a>'; +	} +	public static function phpErrorHandler($errno,$errstr,$errfile,$errline) +	{ +		if(error_reporting()!=0) +			throw new TPhpErrorException($errno,$errstr,$errfile,$errline); +	} +	public static function exceptionHandler($exception) +	{ +		if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null) +		{ +			$errorHandler->handleError(null,$exception); +		} +		else +		{ +			echo $exception; +		} +		exit(1); +	} +	public static function setApplication($application) +	{ +		if(self::$_application!==null) +			throw new TInvalidOperationException('prado_application_singleton_required'); +		self::$_application=$application; +	} +	public static function getApplication() +	{ +		return self::$_application; +	} +	public static function getFrameworkPath() +	{ +		return PRADO_DIR; +	} +	public static function serialize($data) +	{ +		$arr[0]=$data; +		return serialize($arr); +	} +	public static function unserialize($str) +	{ +		$arr=unserialize($str); +		return isset($arr[0])?$arr[0]:null; +	} +	public static function createComponent($type) +	{ +		self::using($type); +		if(($pos=strrpos($type,'.'))!==false) +			$type=substr($type,$pos+1); +		if(($n=func_num_args())>1) +		{ +			$args=func_get_args(); +			$s='$args[1]'; +			for($i=2;$i<$n;++$i) +				$s.=",\$args[$i]"; +			eval("\$component=new $type($s);"); +			return $component; +		} +		else +			return new $type; +	} +	public static function using($namespace,$checkClassExistence=true) +	{ +		if(isset(self::$_usings[$namespace]) || class_exists($namespace,false)) +			return; +		if(($pos=strrpos($namespace,'.'))===false)  		{ +			try +			{ +				include_once($namespace.self::CLASS_FILE_EXT); +			} +			catch(Exception $e) +			{ +				if($checkClassExistence && !class_exists($namespace,false)) +					throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage()); +				else +					throw $e; +			} +		} +		else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null) +		{ +			$className=substr($namespace,$pos+1); +			if($className==='*')  			{ +				self::$_usings[$namespace]=$path; +				set_include_path(get_include_path().PATH_SEPARATOR.$path); +			} +			else  			{ +				self::$_usings[$namespace]=$path; +				if(!$checkClassExistence || !class_exists($className,false)) +				{ +					try +					{ +						include_once($path); +					} +					catch(Exception $e) +					{ +						if($checkClassExistence && !class_exists($className,false)) +							throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage()); +						else +							throw $e; +					} +				} +			} +		} +		else +			throw new TInvalidDataValueException('prado_using_invalid',$namespace); +	} +	public static function getPathOfNamespace($namespace,$ext='') +	{ +		if(isset(self::$_usings[$namespace])) +			return self::$_usings[$namespace]; +		else if(isset(self::$_aliases[$namespace])) +			return self::$_aliases[$namespace]; +		else +		{ +			$segs=explode('.',$namespace); +			$alias=array_shift($segs); +			if(($file=array_pop($segs))!==null && ($root=self::getPathOfAlias($alias))!==null) +				return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file==='*')?'':DIRECTORY_SEPARATOR.$file.$ext); +			else +				return null; +		} +	} +	public static function getPathOfAlias($alias) +	{ +		return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null; +	} +	protected static function getPathAliases() +	{ +		return self::$_aliases; +	} +	public static function setPathOfAlias($alias,$path) +	{ +		if(isset(self::$_aliases[$alias])) +			throw new TInvalidOperationException('prado_alias_redefined',$alias); +		else if(($rp=realpath($path))!==false && is_dir($rp)) +		{ +			if(strpos($alias,'.')===false) +				self::$_aliases[$alias]=$rp; +			else +				throw new TInvalidDataValueException('prado_aliasname_invalid',$alias); +		} +		else +			throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path); +	} +	public static function fatalError($msg) +	{ +		echo '<h1>Fatal Error</h1>'; +		echo '<p>'.$msg.'</p>'; +		if(!function_exists('debug_backtrace')) +			return; +		echo '<h2>Debug Backtrace</h2>'; +		echo '<pre>'; +		$index=-1; +		foreach(debug_backtrace() as $t) +		{ +			$index++; +			if($index==0)  				continue; +			echo '#'.$index.' '; +			if(isset($t['file'])) +				echo basename($t['file']) . ':' . $t['line']; +			else +			   echo '<PHP inner-code>'; +			echo ' -- '; +			if(isset($t['class'])) +				echo $t['class'] . $t['type']; +			echo $t['function'] . '('; +			if(isset($t['args']) && sizeof($t['args']) > 0) +			{ +				$count=0; +				foreach($t['args'] as $item) +				{ +					if(is_string($item)) +					{ +						$str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES); +						if (strlen($item) > 70) +							echo "'". substr($str, 0, 70) . "...'"; +						else +							echo "'" . $str . "'"; +					} +					else if (is_int($item) || is_float($item)) +						echo $item; +					else if (is_object($item)) +						echo get_class($item); +					else if (is_array($item)) +						echo 'array(' . count($item) . ')'; +					else if (is_bool($item)) +						echo $item ? 'true' : 'false'; +					else if ($item === null) +						echo 'NULL'; +					else if (is_resource($item)) +						echo get_resource_type($item); +					$count++; +					if (count($t['args']) > $count) +						echo ', '; +				} +			} +			echo ")\n"; +		} +		echo '</pre>'; +		exit(1); +	} +	public static function getUserLanguages() +	{ +		static $languages=null; +		if($languages===null) +		{ +			if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) +				$languages[0]='en'; +			else +			{ +				$languages=array(); +				foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language) +				{ +					$array=explode(';q=',trim($language)); +					$languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0; +				} +				arsort($languages); +				$languages=array_keys($languages); +				if(empty($languages)) +					$languages[0]='en'; +			} +		} +		return $languages; +	} +	public static function getPreferredLanguage() +	{ +		static $language=null; +		if($language===null) +		{ +			$langs=Prado::getUserLanguages(); +			$lang=explode('-',$langs[0]); +			if(empty($lang[0]) || !ctype_alpha($lang[0])) +				$language='en'; +			else +				$language=$lang[0]; +		} +		return $language; +	} +	public static function trace($msg,$category='Uncategorized') +	{ +		if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance) +			return; +		if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug) +		{ +			$trace=debug_backtrace(); +			if(isset($trace[0]['file']) && isset($trace[0]['line'])) +				$msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})"; +			$level=TLogger::DEBUG; +		} +		else +			$level=TLogger::INFO; +		self::log($msg,$level,$category); +	} +	public static function log($msg,$level=TLogger::INFO,$category='Uncategorized') +	{ +		if(self::$_logger===null) +			self::$_logger=new TLogger; +		self::$_logger->log($msg,$level,$category); +	} +	public static function getLogger() +	{ +		if(self::$_logger===null) +			self::$_logger=new TLogger; +		return self::$_logger; +	} +	public static function varDump($var,$depth=10,$highlight=false) +	{ +		Prado::using('System.Util.TVarDumper'); +		return TVarDumper::dump($var,$depth,$highlight); +	} +	public static function localize($text, $parameters=array(), $catalogue=null, $charset=null) +	{ +		Prado::using('System.I18N.Translation'); +		$app = Prado::getApplication()->getGlobalization(false); +		$params = array(); +		foreach($parameters as $key => $value) +			$params['{'.$key.'}'] = $value; +				if($app===null || ($config = $app->getTranslationConfiguration())===null) +			return strtr($text, $params); +		if ($catalogue===null) +			$catalogue=isset($config['catalogue'])?$config['catalogue']:'messages'; +		Translation::init($catalogue); +				$appCharset = $app===null ? '' : $app->getCharset(); +				$defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset(); +				if(empty($charset)) $charset = $appCharset; +		if(empty($charset)) $charset = $defaultCharset; +		return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset); +	} +} +class TReflectionClass extends ReflectionClass +{ +} +PradoBase::using('System.TComponent'); +PradoBase::using('System.Exceptions.TException'); +PradoBase::using('System.Util.TLogger'); +if(!class_exists('Prado',false)) +{ +	class Prado extends PradoBase +	{ +	} +} +spl_autoload_register(array('Prado','autoload')); +Prado::initErrorHandlers(); +interface IModule +{ +	public function init($config); +	public function getID(); +	public function setID($id); +} +interface IService +{ +	public function init($config); +	public function getID(); +	public function setID($id); +	public function getEnabled(); +	public function setEnabled($value); +	public function run(); +} +interface ITextWriter +{ +	public function write($str); +	public function flush(); +} +interface IUser +{ +	public function getName(); +	public function setName($value); +	public function getIsGuest(); +	public function setIsGuest($value); +	public function getRoles(); +	public function setRoles($value); +	public function isInRole($role); +	public function saveToString(); +	public function loadFromString($string); +} +interface IStatePersister +{ +	public function load(); +	public function save($state); +} +interface ICache +{ +	public function get($id); +	public function set($id,$value,$expire=0,$dependency=null); +	public function add($id,$value,$expire=0,$dependency=null); +	public function delete($id); +	public function flush(); +} +interface ICacheDependency +{ +	public function getHasChanged(); +} +interface IRenderable +{ +	public function render($writer); +} +interface IBindable +{ +	public function dataBind(); +} +interface IStyleable +{ +	public function getHasStyle(); +	public function getStyle(); +	public function clearStyle(); +} +interface IActiveControl +{ +	public function getActiveControl(); +} +interface ICallbackEventHandler +{ +	public function raiseCallbackEvent($eventArgument); +} +interface IDataRenderer +{ +	public function getData(); +	public function setData($value); +} +class TApplicationComponent extends TComponent +{ +	public function getApplication() +	{ +		return Prado::getApplication(); +	} +	public function getService() +	{ +		return Prado::getApplication()->getService(); +	} +	public function getRequest() +	{ +		return Prado::getApplication()->getRequest(); +	} +	public function getResponse() +	{ +		return Prado::getApplication()->getResponse(); +	} +	public function getSession() +	{ +		return Prado::getApplication()->getSession(); +	} +	public function getUser() +	{ +		return Prado::getApplication()->getUser(); +	} +	public function publishAsset($assetPath,$className=null) +	{ +		if($className===null) +			$className=get_class($this); +		$class=new ReflectionClass($className); +		$fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath; +		return $this->publishFilePath($fullPath); +	} +	public function publishFilePath($fullPath) +	{ +		return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath); +	} +} +abstract class TModule extends TApplicationComponent implements IModule +{ +	private $_id; +	public function init($config) +	{ +	} +	public function getID() +	{ +		return $this->_id; +	} +	public function setID($value) +	{ +		$this->_id=$value; +	} +} +abstract class TService extends TApplicationComponent implements IService +{ +	private $_id; +	private $_enabled=true; +	public function init($config) +	{ +	} +	public function getID() +	{ +		return $this->_id; +	} +	public function setID($value) +	{ +		$this->_id=$value; +	} +	public function getEnabled() +	{ +		return $this->_enabled; +	} +	public function setEnabled($value) +	{ +		$this->_enabled=TPropertyValue::ensureBoolean($value); +	} +	public function run() +	{ +	} +} +class TErrorHandler extends TModule +{ +	const ERROR_FILE_NAME='error'; +	const EXCEPTION_FILE_NAME='exception'; +	const SOURCE_LINES=12; +	private $_templatePath=null; +	public function init($config) +	{ +		$this->getApplication()->setErrorHandler($this); +	} +	public function getErrorTemplatePath() +	{ +		if($this->_templatePath===null) +			$this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates'; +		return $this->_templatePath; +	} +	public function setErrorTemplatePath($value) +	{ +		if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath)) +			$this->_templatePath=$templatePath; +		else +			throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value); +	} +	public function handleError($sender,$param) +	{ +		static $handling=false; +		restore_error_handler(); +		restore_exception_handler(); +		if($handling) +			$this->handleRecursiveError($param); +		else +		{ +			$handling=true; +			if(($response=$this->getResponse())!==null) +				$response->clear(); +			if(!headers_sent()) +				header('Content-Type: text/html; charset=UTF-8'); +			if($param instanceof THttpException) +				$this->handleExternalError($param->getStatusCode(),$param); +			else if($this->getApplication()->getMode()===TApplicationMode::Debug) +				$this->displayException($param); +			else +				$this->handleExternalError(500,$param); +		} +	} +	protected function handleExternalError($statusCode,$exception) +	{ +		if(!($exception instanceof THttpException)) +			error_log($exception->__toString()); +		$content=$this->getErrorTemplate($statusCode,$exception); +		$serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:''; +		if($this->getApplication()->getMode()===TApplicationMode::Debug) +			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion(); +		else +			$version=''; +		$tokens=array( +			'%%StatusCode%%' => "$statusCode", +			'%%ErrorMessage%%' => htmlspecialchars($exception->getMessage()), +			'%%ServerAdmin%%' => $serverAdmin, +			'%%Version%%' => $version, +			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) +		); +		header("HTTP/1.0 $statusCode ".$exception->getMessage()); +		echo strtr($content,$tokens); +	} +	protected function handleRecursiveError($exception) +	{ +		if($this->getApplication()->getMode()===TApplicationMode::Debug) +		{ +			echo "<html><head><title>Recursive Error</title></head>\n"; +			echo "<body><h1>Recursive Error</h1>\n"; +			echo "<pre>".$exception->__toString()."</pre>\n"; +			echo "</body></html>"; +		} +		else +		{ +			error_log("Error happened while processing an existing error:\n".$exception->__toString()); +			header('HTTP/1.0 500 Internal Error'); +		} +	} +	protected function displayException($exception) +	{ +		if(php_sapi_name()==='cli') +		{ +			echo $exception->getMessage()."\n"; +			echo $exception->getTraceAsString(); +			return; +		} +		if($exception instanceof TTemplateException) +		{ +			$fileName=$exception->getTemplateFile(); +			$lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName); +			$source=$this->getSourceCode($lines,$exception->getLineNumber()); +			if($fileName==='') +				$fileName='---embedded template---'; +			$errorLine=$exception->getLineNumber(); +		} +		else +		{ +			if(($trace=$this->getExactTrace($exception))!==null) +			{ +				$fileName=$trace['file']; +				$errorLine=$trace['line']; +			} +			else +			{ +				$fileName=$exception->getFile(); +				$errorLine=$exception->getLine(); +			} +			$source=$this->getSourceCode(@file($fileName),$errorLine); +		} +		if($this->getApplication()->getMode()===TApplicationMode::Debug) +			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion(); +		else +			$version=''; +		$tokens=array( +			'%%ErrorType%%' => get_class($exception), +			'%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())), +			'%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')', +			'%%SourceCode%%' => $source, +			'%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()), +			'%%Version%%' => $version, +			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) +		); +		$content=$this->getExceptionTemplate($exception); +		echo strtr($content,$tokens); +	} +	protected function getExceptionTemplate($exception) +	{ +		$lang=Prado::getPreferredLanguage(); +		$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html'; +		if(!is_file($exceptionFile)) +			$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html'; +		if(($content=@file_get_contents($exceptionFile))===false) +			die("Unable to open exception template file '$exceptionFile'."); +		return $content; +	} +	protected function getErrorTemplate($statusCode,$exception) +	{ +		$base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME; +		$lang=Prado::getPreferredLanguage(); +		if(is_file("$base$statusCode-$lang.html")) +			$errorFile="$base$statusCode-$lang.html"; +		else if(is_file("$base$statusCode.html")) +			$errorFile="$base$statusCode.html"; +		else if(is_file("$base-$lang.html")) +			$errorFile="$base-$lang.html"; +		else +			$errorFile="$base.html"; +		if(($content=@file_get_contents($errorFile))===false) +			die("Unable to open error template file '$errorFile'."); +		return $content; +	} +	private function getExactTrace($exception) +	{ +		$trace=$exception->getTrace(); +		$result=null; +		if($exception instanceof TPhpErrorException) +			$result=isset($trace[0]['file'])?$trace[0]:$trace[1]; +		else if($exception instanceof TInvalidOperationException) +		{ +			if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null) +				$result=$this->getPropertyAccessTrace($trace,'__set'); +		} +		if($result!==null && strpos($result['file'],': eval()\'d code')!==false) +			return null; +		return $result; +	} +	private function getPropertyAccessTrace($trace,$pattern) +	{ +		$result=null; +		foreach($trace as $t) +		{ +			if(isset($t['function']) && $t['function']===$pattern) +				$result=$t; +			else +				break; +		} +		return $result; +	} +	private function getSourceCode($lines,$errorLine) +	{ +		$beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0; +		$endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines); +		$source=''; +		for($i=$beginLine;$i<$endLine;++$i) +		{ +			if($i===$errorLine-1) +			{ +				$line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i]))); +				$source.="<div class=\"error\">".$line."</div>"; +			} +			else +				$source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i]))); +		} +		return $source; +	} +	private function addLink($message) +	{ +		$baseUrl='http://www.pradosoft.com/docs/classdoc'; +		return preg_replace('/\b(T[A-Z]\w+)\b/',"<a href=\"$baseUrl/\${1}\" target=\"_blank\">\${1}</a>",$message); +	} +} +class TList extends TComponent implements IteratorAggregate,ArrayAccess,Countable +{ +	private $_d=array(); +	private $_c=0; +	private $_r=false; +	public function __construct($data=null,$readOnly=false) +	{ +		if($data!==null) +			$this->copyFrom($data); +		$this->setReadOnly($readOnly); +	} +	public function getReadOnly() +	{ +		return $this->_r; +	} +	protected function setReadOnly($value) +	{ +		$this->_r=TPropertyValue::ensureBoolean($value); +	} +	public function getIterator() +	{ +		return new TListIterator($this->_d); +	} +	public function count() +	{ +		return $this->getCount(); +	} +	public function getCount() +	{ +		return $this->_c; +	} +	public function itemAt($index) +	{ +		if($index>=0 && $index<$this->_c) +			return $this->_d[$index]; +		else +			throw new TInvalidDataValueException('list_index_invalid',$index); +	} +	public function add($item) +	{ +		$this->insertAt($this->_c,$item); +		return $this->_c-1; +	} +	public function insertAt($index,$item) +	{ +		if(!$this->_r) +		{ +			if($index===$this->_c) +				$this->_d[$this->_c++]=$item; +			else if($index>=0 && $index<$this->_c) +			{ +				array_splice($this->_d,$index,0,array($item)); +				$this->_c++; +			} +			else +				throw new TInvalidDataValueException('list_index_invalid',$index); +		} +		else +			throw new TInvalidOperationException('list_readonly',get_class($this)); +	} +	public function remove($item) +	{ +		if(($index=$this->indexOf($item))>=0) +		{ +			$this->removeAt($index); +			return $index; +		} +		else +			throw new TInvalidDataValueException('list_item_inexistent'); +	} +	public function removeAt($index) +	{ +		if(!$this->_r) +		{ +			if($index>=0 && $index<$this->_c) +			{ +				$this->_c--; +				if($index===$this->_c) +					return array_pop($this->_d); +				else +				{ +					$item=$this->_d[$index]; +					array_splice($this->_d,$index,1); +					return $item; +				} +			} +			else +				throw new TInvalidDataValueException('list_index_invalid',$index); +		} +		else +			throw new TInvalidOperationException('list_readonly',get_class($this)); +	} +	public function clear() +	{ +		for($i=$this->_c-1;$i>=0;--$i) +			$this->removeAt($i); +	} +	public function contains($item) +	{ +		return $this->indexOf($item)>=0; +	} +	public function indexOf($item) +	{ +		if(($index=array_search($item,$this->_d,true))===false) +			return -1; +		else +			return $index; +	} +	public function toArray() +	{ +		return $this->_d; +	} +	public function copyFrom($data) +	{ +		if(is_array($data) || ($data instanceof Traversable)) +		{ +			if($this->_c>0) +				$this->clear(); +			foreach($data as $item) +				$this->add($item); +		} +		else if($data!==null) +			throw new TInvalidDataTypeException('list_data_not_iterable'); +	} +	public function mergeWith($data) +	{ +		if(is_array($data) || ($data instanceof Traversable)) +		{ +			foreach($data as $item) +				$this->add($item); +		} +		else if($data!==null) +			throw new TInvalidDataTypeException('list_data_not_iterable'); +	} +	public function offsetExists($offset) +	{ +		return ($offset>=0 && $offset<$this->_c); +	} +	public function offsetGet($offset) +	{ +		return $this->itemAt($offset); +	} +	public function offsetSet($offset,$item) +	{ +		if($offset===null || $offset===$this->_c) +			$this->insertAt($this->_c,$item); +		else +		{ +			$this->removeAt($offset); +			$this->insertAt($offset,$item); +		} +	} +	public function offsetUnset($offset) +	{ +		$this->removeAt($offset); +	} +} +class TListIterator implements Iterator +{ +	private $_d; +	private $_i; +	private $_c; +	public function __construct(&$data) +	{ +		$this->_d=&$data; +		$this->_i=0; +		$this->_c=count($this->_d); +	} +	public function rewind() +	{ +		$this->_i=0; +	} +	public function key() +	{ +		return $this->_i; +	} +	public function current() +	{ +		return $this->_d[$this->_i]; +	} +	public function next() +	{ +		$this->_i++; +	} +	public function valid() +	{ +		return $this->_i<$this->_c; +	} +} +abstract class TCache extends TModule implements ICache, ArrayAccess +{ +	private $_prefix=null; +	private $_primary=true; +	public function init($config) +	{ +		if($this->_prefix===null) +			$this->_prefix=$this->getApplication()->getUniqueID(); +		if($this->_primary) +		{ +			if($this->getApplication()->getCache()===null) +				$this->getApplication()->setCache($this); +			else +				throw new TConfigurationException('cache_primary_duplicated',get_class($this)); +		} +	} +	public function getPrimaryCache() +	{ +		return $this->_primary; +	} +	public function setPrimaryCache($value) +	{ +		$this->_primary=TPropertyValue::ensureBoolean($value); +	} +	public function getKeyPrefix() +	{ +		return $this->_prefix; +	} +	public function setKeyPrefix($value) +	{ +		$this->_prefix=$value; +	} +	protected function generateUniqueKey($key) +	{ +		return md5($this->_prefix.$key); +	} +	public function get($id) +	{ +		if(($value=$this->getValue($this->generateUniqueKey($id)))!==false) +		{ +			$data=unserialize($value); +			if(!is_array($data)) +				return false; +			if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged()) +				return $data[0]; +		} +		return false; +	} +	public function set($id,$value,$expire=0,$dependency=null) +	{ +		if(empty($value) && $expire === 0) +			$this->delete($id); +		else +		{ +			$data=array($value,$dependency); +			return $this->setValue($this->generateUniqueKey($id),serialize($data),$expire); +		} +	} +	public function add($id,$value,$expire=0,$dependency=null) +	{ +		if(empty($value) && $expire === 0) +			return false; +		$data=array($value,$dependency); +		return $this->addValue($this->generateUniqueKey($id),serialize($data),$expire); +	} +	public function delete($id) +	{ +		return $this->deleteValue($this->generateUniqueKey($id)); +	} +	public function flush() +	{ +		throw new TNotSupportedException('cache_flush_unsupported'); +	} +	abstract protected function getValue($key); +	abstract protected function setValue($key,$value,$expire); +	abstract protected function addValue($key,$value,$expire); +	abstract protected function deleteValue($key); +	public function offsetExists($id) +	{ +		return $this->get($id) !== false; +	} +	public function offsetGet($id) +	{ +		return $this->get($id); +	} +	public function offsetSet($id, $value) +	{ +		$this->set($id, $value); +	} +	public function offsetUnset($id) +	{ +		$this->delete($id); +	} +} +abstract class TCacheDependency extends TComponent implements ICacheDependency +{ +} +class TFileCacheDependency extends TCacheDependency +{ +	private $_fileName; +	private $_timestamp; +	public function __construct($fileName) +	{ +		$this->setFileName($fileName); +	} +	public function getFileName() +	{ +		return $this->_fileName; +	} +	public function setFileName($value) +	{ +		$this->_fileName=$value; +		$this->_timestamp=@filemtime($value); +	} +	public function getTimestamp() +	{ +		return $this->_timestamp; +	} +	public function getHasChanged() +	{ +		return @filemtime($this->_fileName)!==$this->_timestamp; +	} +} +class TDirectoryCacheDependency extends TCacheDependency +{ +	private $_recursiveCheck=true; +	private $_recursiveLevel=-1; +	private $_timestamps; +	private $_directory; +	public function __construct($directory) +	{ +		$this->setDirectory($directory); +	} +	public function getDirectory() +	{ +		return $this->_directory; +	} +	public function setDirectory($directory) +	{ +		if(($path=realpath($directory))===false || !is_dir($path)) +			throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory); +		$this->_directory=$path; +		$this->_timestamps=$this->generateTimestamps($path); +	} +	public function getRecursiveCheck() +	{ +		return $this->_recursiveCheck; +	} +	public function setRecursiveCheck($value) +	{ +		$this->_recursiveCheck=TPropertyValue::ensureBoolean($value); +	} +	public function getRecursiveLevel() +	{ +		return $this->_recursiveLevel; +	} +	public function setRecursiveLevel($value) +	{ +		$this->_recursiveLevel=TPropertyValue::ensureInteger($value); +	} +	public function getHasChanged() +	{ +		return $this->generateTimestamps($this->_directory)!=$this->_timestamps; +	} +	protected function validateFile($fileName) +	{ +		return true; +	} +	protected function validateDirectory($directory) +	{ +		return true; +	} +	protected function generateTimestamps($directory,$level=0) +	{ +		if(($dir=opendir($directory))===false) +			throw new TIOException('directorycachedependency_directory_invalid',$directory); +		$timestamps=array(); +		while(($file=readdir($dir))!==false) +		{ +			$path=$directory.DIRECTORY_SEPARATOR.$file; +			if($file==='.' || $file==='..') +				continue; +			else if(is_dir($path)) +			{ +				if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path)) +					$timestamps=array_merge($this->generateTimestamps($path,$level+1)); +			} +			else if($this->validateFile($path)) +				$timestamps[$path]=filemtime($path); +		} +		closedir($dir); +		return $timestamps; +	} +} +class TGlobalStateCacheDependency extends TCacheDependency +{ +	private $_stateName; +	private $_stateValue; +	public function __construct($name) +	{ +		$this->setStateName($name); +	} +	public function getStateName() +	{ +		return $this->_stateName; +	} +	public function setStateName($value) +	{ +		$this->_stateName=$value; +		$this->_stateValue=Prado::getApplication()->getGlobalState($value); +	} +	public function getHasChanged() +	{ +		return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName); +	} +} +class TChainedCacheDependency extends TCacheDependency +{ +	private $_dependencies=null; +	public function getDependencies() +	{ +		if($this->_dependencies===null) +			$this->_dependencies=new TCacheDependencyList; +		return $this->_dependencies; +	} +	public function getHasChanged() +	{ +		if($this->_dependencies!==null) +		{ +			foreach($this->_dependencies as $dependency) +				if($dependency->getHasChanged()) +					return true; +		} +		return false; +	} +} +class TApplicationStateCacheDependency extends TCacheDependency +{ +	public function getHasChanged() +	{ +		return Prado::getApplication()->getMode()!==TApplicationMode::Performance; +	} +} +class TCacheDependencyList extends TList +{ +	public function insertAt($index,$item) +	{ +		if($item instanceof ICacheDependency) +			parent::insertAt($index,$item); +		else +			throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required'); +	} +} +class TTextWriter extends TComponent implements ITextWriter +{ +	private $_str=''; +	public function flush() +	{ +		$str=$this->_str; +		$this->_str=''; +		return $str; +	} +	public function write($str) +	{ +		$this->_str.=$str; +	} +	public function writeLine($str='') +	{ +		$this->write($str."\n"); +	} +} +class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable +{ +	private $_d=array(); +	private $_r=false; +	public function __construct($data=null,$readOnly=false) +	{ +		if($data!==null) +			$this->copyFrom($data); +		$this->setReadOnly($readOnly); +	} +	public function getReadOnly() +	{ +		return $this->_r; +	} +	protected function setReadOnly($value) +	{ +		$this->_r=TPropertyValue::ensureBoolean($value); +	} +	public function getIterator() +	{ +		return new TMapIterator($this->_d); +	} +	public function count() +	{ +		return $this->getCount(); +	} +	public function getCount() +	{ +		return count($this->_d); +	} +	public function getKeys() +	{ +		return array_keys($this->_d); +	} +	public function itemAt($key) +	{ +		return isset($this->_d[$key]) ? $this->_d[$key] : null; +	} +	public function add($key,$value) +	{ +		if(!$this->_r) +			$this->_d[$key]=$value; +		else +			throw new TInvalidOperationException('map_readonly',get_class($this)); +	} +	public function remove($key) +	{ +		if(!$this->_r) +		{ +			if(isset($this->_d[$key]) || array_key_exists($key,$this->_d)) +			{ +				$value=$this->_d[$key]; +				unset($this->_d[$key]); +				return $value; +			} +			else +				return null; +		} +		else +			throw new TInvalidOperationException('map_readonly',get_class($this)); +	} +	public function clear() +	{ +		foreach(array_keys($this->_d) as $key) +			$this->remove($key); +	} +	public function contains($key) +	{ +		return isset($this->_d[$key]) || array_key_exists($key,$this->_d); +	} +	public function toArray() +	{ +		return $this->_d; +	} +	public function copyFrom($data) +	{ +		if(is_array($data) || $data instanceof Traversable) +		{ +			if($this->getCount()>0) +				$this->clear(); +			foreach($data as $key=>$value) +				$this->add($key,$value); +		} +		else if($data!==null) +			throw new TInvalidDataTypeException('map_data_not_iterable'); +	} +	public function mergeWith($data) +	{ +		if(is_array($data) || $data instanceof Traversable) +		{ +			foreach($data as $key=>$value) +				$this->add($key,$value); +		} +		else if($data!==null) +			throw new TInvalidDataTypeException('map_data_not_iterable'); +	} +	public function offsetExists($offset) +	{ +		return $this->contains($offset); +	} +	public function offsetGet($offset) +	{ +		return $this->itemAt($offset); +	} +	public function offsetSet($offset,$item) +	{ +		$this->add($offset,$item); +	} +	public function offsetUnset($offset) +	{ +		$this->remove($offset); +	} +} +class TMapIterator implements Iterator +{ +	private $_d; +	private $_keys; +	private $_key; +	public function __construct(&$data) +	{ +		$this->_d=&$data; +		$this->_keys=array_keys($data); +	} +	public function rewind() +	{ +		$this->_key=reset($this->_keys); +	} +	public function key() +	{ +		return $this->_key; +	} +	public function current() +	{ +		return $this->_d[$this->_key]; +	} +	public function next() +	{ +		$this->_key=next($this->_keys); +	} +	public function valid() +	{ +		return $this->_key!==false; +	} +} +class TStack extends TComponent implements IteratorAggregate,Countable +{ +	private $_d=array(); +	private $_c=0; +	public function __construct($data=null) +	{ +		if($data!==null) +			$this->copyFrom($data); +	} +	public function toArray() +	{ +		return $this->_d; +	} +	public function copyFrom($data) +	{ +		if(is_array($data) || ($data instanceof Traversable)) +		{ +			$this->clear(); +			foreach($data as $item) +			{ +				$this->_d[]=$item; +				++$this->_c; +			} +		} +		else if($data!==null) +			throw new TInvalidDataTypeException('stack_data_not_iterable'); +	} +	public function clear() +	{ +		$this->_c=0; +		$this->_d=array(); +	} +	public function contains($item) +	{ +		return array_search($item,$this->_d,true)!==false; +	} +	public function peek() +	{ +		if($this->_c===0) +			throw new TInvalidOperationException('stack_empty'); +		else +			return $this->_d[$this->_c-1]; +	} +	public function pop() +	{ +		if($this->_c===0) +			throw new TInvalidOperationException('stack_empty'); +		else +		{ +			--$this->_c; +			return array_pop($this->_d); +		} +	} +	public function push($item) +	{ +		++$this->_c; +		$this->_d[] = $item; +	} +	public function getIterator() +	{ +		return new TStackIterator($this->_d); +	} +	public function getCount() +	{ +		return $this->_c; +	} +	public function count() +	{ +		return $this->getCount(); +	} +} +class TStackIterator implements Iterator +{ +	private $_d; +	private $_i; +	private $_c; +	public function __construct(&$data) +	{ +		$this->_d=&$data; +		$this->_i=0; +		$this->_c=count($this->_d); +	} +	public function rewind() +	{ +		$this->_i=0; +	} +	public function key() +	{ +		return $this->_i; +	} +	public function current() +	{ +		return $this->_d[$this->_i]; +	} +	public function next() +	{ +		$this->_i++; +	} +	public function valid() +	{ +		return $this->_i<$this->_c; +	} +} +class TXmlElement extends TComponent +{ +	private $_parent=null; +	private $_tagName='unknown'; +	private $_value=''; +	private $_elements=null; +	private $_attributes=null; +	public function __construct($tagName) +	{ +		$this->setTagName($tagName); +	} +	public function getParent() +	{ +		return $this->_parent; +	} +	public function setParent($parent) +	{ +		$this->_parent=$parent; +	} +	public function getTagName() +	{ +		return $this->_tagName; +	} +	public function setTagName($tagName) +	{ +		$this->_tagName=$tagName; +	} +	public function getValue() +	{ +		return $this->_value; +	} +	public function setValue($value) +	{ +		$this->_value=$value; +	} +	public function getHasElement() +	{ +		return $this->_elements!==null && $this->_elements->getCount()>0; +	} +	public function getHasAttribute() +	{ +		return $this->_attributes!==null && $this->_attributes->getCount()>0; +	} +	public function getAttribute($name) +	{ +		if($this->_attributes!==null) +			return $this->_attributes->itemAt($name); +		else +			return null; +	} +	public function setAttribute($name,$value) +	{ +		$this->getAttributes()->add($name,$value); +	} +	public function getElements() +	{ +		if(!$this->_elements) +			$this->_elements=new TXmlElementList($this); +		return $this->_elements; +	} +	public function getAttributes() +	{ +		if(!$this->_attributes) +			$this->_attributes=new TMap; +		return $this->_attributes; +	} +	public function getElementByTagName($tagName) +	{ +		if($this->_elements) +		{ +			foreach($this->_elements as $element) +				if($element->_tagName===$tagName) +					return $element; +		} +		return null; +	} +	public function getElementsByTagName($tagName) +	{ +		$list=new TList; +		if($this->_elements) +		{ +			foreach($this->_elements as $element) +				if($element->_tagName===$tagName) +					$list->add($element); +		} +		return $list; +	} +	public function toString($indent=0) +	{ +		$attr=''; +		if($this->_attributes!==null) +		{ +			foreach($this->_attributes as $name=>$value) +			{ +				$value=$this->xmlEncode($value); +				$attr.=" $name=\"$value\""; +			} +		} +		$prefix=str_repeat(' ',$indent*4); +		if($this->getHasElement()) +		{ +			$str=$prefix."<{$this->_tagName}$attr>\n"; +			foreach($this->getElements() as $element) +				$str.=$element->toString($indent+1)."\n"; +			$str.=$prefix."</{$this->_tagName}>"; +			return $str; +		} +		else if(($value=$this->getValue())!=='') +		{ +			$value=$this->xmlEncode($value); +			return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>"; +		} +		else +			return $prefix."<{$this->_tagName}$attr />"; +	} +	public function __toString() +	{ +		return $this->toString(); +	} +	private function xmlEncode($str) +	{ +		return strtr($str,array( +			'>'=>'>', +			'<'=>'<', +			'&'=>'&', +			'"'=>'"', +			"\r"=>'
', +			"\t"=>'	', +			"\n"=>'
')); +	} +} +class TXmlDocument extends TXmlElement +{ +	private $_version; +	private $_encoding; +	public function __construct($version='1.0',$encoding='') +	{ +		parent::__construct(''); +		$this->setVersion($version); +		$this->setEncoding($encoding); +	} +	public function getVersion() +	{ +		return $this->_version; +	} +	public function setVersion($version) +	{ +		$this->_version=$version; +	} +	public function getEncoding() +	{ +		return $this->_encoding; +	} +	public function setEncoding($encoding) +	{ +		$this->_encoding=$encoding; +	} +	public function loadFromFile($file) +	{ +		if(($str=@file_get_contents($file))!==false) +			return $this->loadFromString($str); +		else +			throw new TIOException('xmldocument_file_read_failed',$file); +	} +	public function loadFromString($string) +	{ +				$doc=new DOMDocument(); +		if($doc->loadXML($string)===false) +			return false; +		$this->setEncoding($doc->encoding); +		$this->setVersion($doc->version); +		$element=$doc->documentElement; +		$this->setTagName($element->tagName); +		$this->setValue($element->nodeValue); +		$elements=$this->getElements(); +		$attributes=$this->getAttributes(); +		$elements->clear(); +		$attributes->clear(); +		static $bSimpleXml; +		if($bSimpleXml === null) +			$bSimpleXml = (boolean)function_exists('simplexml_load_string'); +		if($bSimpleXml) +		{ +			$simpleDoc = simplexml_load_string($string); +			$docNamespaces = $simpleDoc->getDocNamespaces(false); +			$simpleDoc = null; +			foreach($docNamespaces as $prefix => $uri) +			{ + 				if($prefix === '') +   					$attributes->add('xmlns', $uri); +   				else +   					$attributes->add('xmlns:'.$prefix, $uri); +			} +		} +		foreach($element->attributes as $name=>$attr) +			$attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value); +		foreach($element->childNodes as $child) +		{ +			if($child instanceof DOMElement) +				$elements->add($this->buildElement($child)); +		} +		return true; +	} +	public function saveToFile($file) +	{ +		if(($fw=fopen($file,'w'))!==false) +		{ +			fwrite($fw,$this->saveToString()); +			fclose($fw); +		} +		else +			throw new TIOException('xmldocument_file_write_failed',$file); +	} +	public function saveToString() +	{ +		$version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"'; +		$encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"'; +		return "<?xml{$version}{$encoding}?>\n".$this->toString(0); +	} +	public function __toString() +	{ +		return $this->saveToString(); +	} +	private function buildElement($node) +	{ +		$element=new TXmlElement($node->tagName); +		$element->setValue($node->nodeValue); +		foreach($node->attributes as $name=>$attr) +			$element->getAttributes()->add(($attr->prefix === '' ? '' : $attr->prefix . ':') . $name,$attr->value); +		foreach($node->childNodes as $child) +		{ +			if($child instanceof DOMElement) +				$element->getElements()->add($this->buildElement($child)); +		} +		return $element; +	} +} +class TXmlElementList extends TList +{ +	private $_o; +	public function __construct(TXmlElement $owner) +	{ +		$this->_o=$owner; +	} +	protected function getOwner() +	{ +		return $this->_o; +	} +	public function insertAt($index,$item) +	{ +		if($item instanceof TXmlElement) +		{ +			parent::insertAt($index,$item); +			if($item->getParent()!==null) +				$item->getParent()->getElements()->remove($item); +			$item->setParent($this->_o); +		} +		else +			throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required'); +	} +	public function removeAt($index) +	{ +		$item=parent::removeAt($index); +		if($item instanceof TXmlElement) +			$item->setParent(null); +		return $item; +	} +} +class TAuthorizationRule extends TComponent +{ +	private $_action; +	private $_users; +	private $_roles; +	private $_verb; +	private $_ipRules; +	private $_everyone; +	private $_guest; +	private $_authenticated; +	public function __construct($action,$users,$roles,$verb='',$ipRules='') +	{ +		$action=strtolower(trim($action)); +		if($action==='allow' || $action==='deny') +			$this->_action=$action; +		else +			throw new TInvalidDataValueException('authorizationrule_action_invalid',$action); +		$this->_users=array(); +		$this->_roles=array(); +		$this->_ipRules=array(); +		$this->_everyone=false; +		$this->_guest=false; +		$this->_authenticated=false; +		if(trim($users)==='') +			$users='*'; +		foreach(explode(',',$users) as $user) +		{ +			if(($user=trim(strtolower($user)))!=='') +			{ +				if($user==='*') +				{ +					$this->_everyone=true; +					break; +				} +				else if($user==='?') +					$this->_guest=true; +				else if($user==='@') +					$this->_authenticated=true; +				else +					$this->_users[]=$user; +			} +		} +		if(trim($roles)==='') +			$roles='*'; +		foreach(explode(',',$roles) as $role) +		{ +			if(($role=trim(strtolower($role)))!=='') +				$this->_roles[]=$role; +		} +		if(($verb=trim(strtolower($verb)))==='') +			$verb='*'; +		if($verb==='*' || $verb==='get' || $verb==='post') +			$this->_verb=$verb; +		else +			throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb); +		if(trim($ipRules)==='') +			$ipRules='*'; +		foreach(explode(',',$ipRules) as $ipRule) +		{ +			if(($ipRule=trim($ipRule))!=='') +				$this->_ipRules[]=$ipRule; +		} +	} +	public function getAction() +	{ +		return $this->_action; +	} +	public function getUsers() +	{ +		return $this->_users; +	} +	public function getRoles() +	{ +		return $this->_roles; +	} +	public function getVerb() +	{ +		return $this->_verb; +	} +	public function getIPRules() +	{ +		return $this->_ipRules; +	} +	public function getGuestApplied() +	{ +		return $this->_guest || $this->_everyone; +	} +	public function getEveryoneApplied() +	{ +		return $this->_everyone; +	} +	public function getAuthenticatedApplied() +	{ +		return $this->_authenticated || $this->_everyone; +	} +	public function isUserAllowed(IUser $user,$verb,$ip) +	{ +		if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user)) +			return ($this->_action==='allow')?1:-1; +		else +			return 0; +	} +	private function isIpMatched($ip) +	{ +		if(empty($this->_ipRules)) +			return 1; +		foreach($this->_ipRules as $rule) +		{ +			if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0)) +				return 1; +		} +		return 0; +	} +	private function isUserMatched($user) +	{ +		return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users)); +	} +	private function isRoleMatched($user) +	{ +		foreach($this->_roles as $role) +		{ +			if($role==='*' || $user->isInRole($role)) +				return true; +		} +		return false; +	} +	private function isVerbMatched($verb) +	{ +		return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0); +	} +} +class TAuthorizationRuleCollection extends TList +{ +	public function isUserAllowed($user,$verb,$ip) +	{ +		if($user instanceof IUser) +		{ +			$verb=strtolower(trim($verb)); +			foreach($this as $rule) +			{ +				if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0) +					return ($decision>0); +			} +			return true; +		} +		else +			return false; +	} +	public function insertAt($index,$item) +	{ +		if($item instanceof TAuthorizationRule) +			parent::insertAt($index,$item); +		else +			throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required'); +	} +} +class TSecurityManager extends TModule +{ +	const STATE_VALIDATION_KEY='prado:securitymanager:validationkey'; +	const STATE_ENCRYPTION_KEY='prado:securitymanager:encryptionkey'; +	private $_validationKey=null; +	private $_encryptionKey=null; +	private $_validation=TSecurityManagerValidationMode::SHA1; +	private $_encryption='3DES'; +	public function init($config) +	{ +		$this->getApplication()->setSecurityManager($this); +	} +	protected function generateRandomKey() +	{ +		return rand().rand().rand().rand(); +	} +	public function getValidationKey() +	{ +		if($this->_validationKey===null) +		{ +			if(($this->_validationKey=$this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))===null) +			{ +				$this->_validationKey=$this->generateRandomKey(); +				$this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY,$this->_validationKey,null); +			} +		} +		return $this->_validationKey; +	} +	public function setValidationKey($value) +	{ +		if($value!=='') +			$this->_validationKey=$value; +		else +			throw new TInvalidDataValueException('securitymanager_validationkey_invalid'); +	} +	public function getEncryptionKey() +	{ +		if($this->_encryptionKey===null) +		{ +			if(($this->_encryptionKey=$this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))===null) +			{ +				$this->_encryptionKey=$this->generateRandomKey(); +				$this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY,$this->_encryptionKey,null); +			} +		} +		return $this->_encryptionKey; +	} +	public function setEncryptionKey($value) +	{ +		if($value!=='') +			$this->_encryptionKey=$value; +		else +			throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid'); +	} +	public function getValidation() +	{ +		return $this->_validation; +	} +	public function setValidation($value) +	{ +		$this->_validation=TPropertyValue::ensureEnum($value,'TSecurityManagerValidationMode'); +	} +	public function getEncryption() +	{ +		return $this->_encryption; +	} +	public function setEncryption($value) +	{ +		throw new TNotSupportedException('Currently only 3DES encryption is supported'); +	} +	public function encrypt($data) +	{ +		if(function_exists('mcrypt_encrypt')) +		{ +			$module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, ''); +			$key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module)); +			srand(); +			$iv=mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND); +			mcrypt_generic_init($module,$key,$iv); +			$encrypted=$iv.mcrypt_generic($module,$data); +			mcrypt_generic_deinit($module); +			mcrypt_module_close($module); +			return $encrypted; +		} +		else +			throw new TNotSupportedException('securitymanager_mcryptextension_required'); +	} +	public function decrypt($data) +	{ +		if(function_exists('mcrypt_decrypt')) +		{ +			$module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, ''); +			$key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module)); +			$ivSize=mcrypt_enc_get_iv_size($module); +			$iv=substr($data,0,$ivSize); +			mcrypt_generic_init($module,$key,$iv); +			$decrypted=mdecrypt_generic($module,substr($data,$ivSize)); +			mcrypt_generic_deinit($module); +			mcrypt_module_close($module); +			return rtrim($decrypted,"\0"); +		} +		else +			throw new TNotSupportedException('securitymanager_mcryptextension_required'); +	} +	public function hashData($data) +	{ +		$hmac=$this->computeHMAC($data); +		return $hmac.$data; +	} +	public function validateData($data) +	{ +		$len=$this->_validation==='SHA1'?40:32; +		if(strlen($data)>=$len) +		{ +			$hmac=substr($data,0,$len); +			$data2=substr($data,$len); +			return $hmac===$this->computeHMAC($data2)?$data2:false; +		} +		else +			return false; +	} +	protected function computeHMAC($data) +	{ +		if($this->_validation==='SHA1') +		{ +			$pack='H40'; +			$func='sha1'; +		} +		else +		{ +			$pack='H32'; +			$func='md5'; +		} +		$key=$this->getValidationKey(); +		$key=str_pad($func($key), 64, chr(0)); +		return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data))); +	} +} +class TSecurityManagerValidationMode extends TEnumerable +{ +	const MD5='MD5'; +	const SHA1='SHA1'; +} +class THttpUtility +{ +	private static $_encodeTable=array('<'=>'<','>'=>'>','"'=>'"'); +	private static $_decodeTable=array('<'=>'<','>'=>'>','"'=>'"'); +	public static function htmlEncode($s) +	{ +		return strtr($s,self::$_encodeTable); +	} +	public static function htmlDecode($s) +	{ +		return strtr($s,self::$_decodeTable); +	} +} +class TJavaScript +{ +	private static $_json; +	public static function renderScriptFiles($files) +	{ +		$str=''; +		foreach($files as $file) +			$str.= self::renderScriptFile($file); +		return $str; +	} +	public static function renderScriptFile($file) +	{ +		return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n"; +	} +	public static function renderScriptBlocks($scripts) +	{ +		if(count($scripts)) +			return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n"; +		else +			return ''; +	} +	public static function renderScriptBlock($script) +	{ +		return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n"; +	} +	public static function quoteString($js,$forUrl=false) +	{ +		if($forUrl) +			return strtr($js,array('%'=>'%25',"\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\')); +		else +			return strtr($js,array("\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\')); +	} +	public static function quoteFunction($js) +	{ +		if(self::isFunction($js)) +			return $js; +		else +			return 'javascript:'.$js; +	} +	public static function isFunction($js) +	{ +		return preg_match('/^\s*javascript:/i', $js); +	} +	public static function encode($value,$toMap=true,$encodeEmptyStrings=false) +	{ +		if(is_string($value)) +		{ +			if(($n=strlen($value))>2) +			{ +				$first=$value[0]; +				$last=$value[$n-1]; +				if(($first==='[' && $last===']') || ($first==='{' && $last==='}')) +					return $value; +			} +			if(self::isFunction($value)) +				return preg_replace('/^\s*javascript:/', '', $value); +			else +				return "'".self::quoteString($value)."'"; +		} +		else if(is_bool($value)) +			return $value?'true':'false'; +		else if(is_array($value)) +		{ +			$results=''; +			if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1)) +			{ +				foreach($value as $k=>$v) +				{ +					if($v!=='' || $encodeEmptyStrings) +					{ +						if($results!=='') +							$results.=','; +						$results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings); +					} +				} +				return '{'.$results.'}'; +			} +			else +			{ +				foreach($value as $v) +				{ +					if($v!=='' || $encodeEmptyStrings) +					{ +						if($results!=='') +							$results.=','; +						$results.=self::encode($v,$toMap, $encodeEmptyStrings); +					} +				} +				return '['.$results.']'; +			} +		} +		else if(is_integer($value)) +			return "$value"; +		else if(is_float($value)) +		{ +			if($value===-INF) +				return 'Number.NEGATIVE_INFINITY'; +			else if($value===INF) +				return 'Number.POSITIVE_INFINITY'; +			else +				return "$value"; +		} +		else if(is_object($value)) +			return self::encode(get_object_vars($value),$toMap); +		else if($value===null) +			return 'null'; +		else +			return ''; +	} +	public static function jsonEncode($value) +	{ +		if(self::$_json === null) +			self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON'); +		return self::$_json->encode($value); +	} +	public static function jsonDecode($value) +	{ +		if(self::$_json === null) +			self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON'); +		return self::$_json->decode($value); +	} +} +class TUrlManager extends TModule +{ +	public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems) +	{ +		$url=$serviceID.'='.urlencode($serviceParam); +		$amp=$encodeAmpersand?'&':'&'; +		$request=$this->getRequest(); +		if(is_array($getItems) || $getItems instanceof Traversable) +		{ +			if($encodeGetItems) +			{ +				foreach($getItems as $name=>$value) +				{ +					if(is_array($value)) +					{ +						$name=urlencode($name.'[]'); +						foreach($value as $v) +							$url.=$amp.$name.'='.urlencode($v); +					} +					else +						$url.=$amp.urlencode($name).'='.urlencode($value); +				} +			} +			else +			{ +				foreach($getItems as $name=>$value) +				{ +					if(is_array($value)) +					{ +						foreach($value as $v) +							$url.=$amp.$name.'[]='.$v; +					} +					else +						$url.=$amp.$name.'='.$value; +				} +			} +		} +		if($request->getUrlFormat()===THttpRequestUrlFormat::Path) +			return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator())); +		else +			return $request->getApplicationUrl().'?'.$url; +	} +	public function parseUrl() +	{ +		$request=$this->getRequest(); +		$pathInfo=trim($request->getPathInfo(),'/'); +		if($request->getUrlFormat()===THttpRequestUrlFormat::Path && $pathInfo!=='') +		{ +			$separator=$request->getUrlParamSeparator(); +			$paths=explode('/',$pathInfo); +			$getVariables=array(); +			foreach($paths as $path) +			{ +				if(($path=trim($path))!=='') +				{ +					if(($pos=strpos($path,$separator))!==false) +					{ +						$name=substr($path,0,$pos); +						$value=substr($path,$pos+1); +						if(($pos=strpos($name,'[]'))!==false) +							$getVariables[substr($name,0,$pos)][]=$value; +						else +							$getVariables[$name]=$value; +					} +					else +						$getVariables[$path]=''; +				} +			} +			return $getVariables; +		} +		else +			return array(); +	} +} +class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule +{ +	private $_urlManager=null; +	private $_urlManagerID=''; +	private $_separator=','; +	private $_serviceID=null; +	private $_serviceParam=null; +	private $_cookies=null; +	private $_requestUri; +	private $_pathInfo; +	private $_cookieOnly=false; +	private $_urlFormat=THttpRequestUrlFormat::Get; +	private $_services; +	private $_requestResolved=false; +	private $_enableCookieValidation=false; +	private $_url=null; +	private $_id; +	private $_items=array(); +	public function getID() +	{ +		return $this->_id; +	} +	public function setID($value) +	{ +		$this->_id=$value; +	} +	public function init($config) +	{ +		if(empty($this->_urlManagerID)) +		{ +			$this->_urlManager=new TUrlManager; +			$this->_urlManager->init(null); +		} +		else +		{ +			$this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID); +			if($this->_urlManager===null) +				throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID); +			if(!($this->_urlManager instanceof TUrlManager)) +				throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID); +		} +				if(php_sapi_name()==='cli') +		{ +			$_SERVER['REMOTE_ADDR']='127.0.0.1'; +			$_SERVER['REQUEST_METHOD']='GET'; +			$_SERVER['SERVER_NAME']='localhost'; +			$_SERVER['SERVER_PORT']=80; +			$_SERVER['HTTP_USER_AGENT']=''; +		} +		$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies'); +														if(isset($_SERVER['REQUEST_URI'])) +			$this->_requestUri=$_SERVER['REQUEST_URI']; +		else  			$this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']); +		if(isset($_SERVER['PATH_INFO'])) +			$this->_pathInfo=$_SERVER['PATH_INFO']; +		else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME']) +			$this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME'])); +		else +			$this->_pathInfo=''; +		if(get_magic_quotes_gpc()) +		{ +			if(isset($_GET)) +				$_GET=$this->stripSlashes($_GET); +			if(isset($_POST)) +				$_POST=$this->stripSlashes($_POST); +			if(isset($_REQUEST)) +				$_REQUEST=$this->stripSlashes($_REQUEST); +			if(isset($_COOKIE)) +				$_COOKIE=$this->stripSlashes($_COOKIE); +		} +		$this->getApplication()->setRequest($this); +	} +	public function stripSlashes(&$data) +	{ +		return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data); +	} +	public function getUrl() +	{ +		if($this->_url===null) +		{ +			$secure=$this->getIsSecureConnection(); +			$url=$secure?'https://':'http://'; +			if(empty($_SERVER['HTTP_HOST'])) +			{ +				$url.=$_SERVER['SERVER_NAME']; +				$port=$_SERVER['SERVER_PORT']; +				if(($port!=80 && !$secure) || ($port!=443 && $secure)) +					$url.=':'.$port; +			} +			else +				$url.=$_SERVER['HTTP_HOST']; +			$url.=$this->getRequestUri(); +			$this->_url=new TUri($url); +		} +		return $this->_url; +	} +	public function getUrlManager() +	{ +		return $this->_urlManagerID; +	} +	public function setUrlManager($value) +	{ +		$this->_urlManagerID=$value; +	} +	public function getUrlManagerModule() +	{ +		return $this->_urlManager; +	} +	public function getUrlFormat() +	{ +		return $this->_urlFormat; +	} +	public function setUrlFormat($value) +	{ +		$this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat'); +	} +	public function getUrlParamSeparator() +	{ +		return $this->_separator; +	} +	public function setUrlParamSeparator($value) +	{ +		if(strlen($value)===1) +			$this->_separator=$value; +		else +			throw new TInvalidDataValueException('httprequest_separator_invalid'); +	} +	public function getRequestType() +	{ +		return $_SERVER['REQUEST_METHOD']; +	} +	public function getIsSecureConnection() +	{ +	    return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off'); +	} +	public function getPathInfo() +	{ +		return $this->_pathInfo; +	} +	public function getQueryString() +	{ +		return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:''; +	} +	public function getHttpProtocolVersion () +	{ +		return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:''; +	} +	public function getRequestUri() +	{ +		return $this->_requestUri; +	} +	public function getBaseUrl($forceSecureConnection=false) +	{ +		$url=$this->getUrl(); +		$scheme=($forceSecureConnection)?"https":$url->getScheme(); +		$host=$url->getHost(); +		if (($port=$url->getPort())) $host.=':'.$port; +		return $scheme.'://'.$host; +	} +	public function getApplicationUrl() +	{ +		return $_SERVER['SCRIPT_NAME']; +	} +	public function getAbsoluteApplicationUrl($forceSecureConnection=false) +	{ +		return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl(); +	} +	public function getApplicationFilePath() +	{ +		return realpath($_SERVER['SCRIPT_FILENAME']); +	} +	public function getServerName() +	{ +		return $_SERVER['SERVER_NAME']; +	} +	public function getServerPort() +	{ +		return $_SERVER['SERVER_PORT']; +	} +	public function getUrlReferrer() +	{ +		return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null; +	} +	public function getBrowser() +	{ +	    try +	    { +		    return get_browser(); +	    } +	    catch(TPhpErrorException $e) +	    { +	        throw new TConfigurationException('httprequest_browscap_required'); +	    } +	} +	public function getUserAgent() +	{ +		return $_SERVER['HTTP_USER_AGENT']; +	} +	public function getUserHostAddress() +	{ +		return $_SERVER['REMOTE_ADDR']; +	} +	public function getUserHost() +	{ +		return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null; +	} +	public function getAcceptTypes() +	{ +				return $_SERVER['HTTP_ACCEPT']; +	} +	public function getUserLanguages() +	{ +		return Prado::getUserLanguages(); +	} +	public function getEnableCookieValidation() +	{ +		return $this->_enableCookieValidation; +	} +	public function setEnableCookieValidation($value) +	{ +		$this->_enableCookieValidation=TPropertyValue::ensureBoolean($value); +	} +	public function getCookies() +	{ +		if($this->_cookies===null) +		{ +			$this->_cookies=new THttpCookieCollection; +			if($this->getEnableCookieValidation()) +			{ +				$sm=$this->getApplication()->getSecurityManager(); +				foreach($_COOKIE as $key=>$value) +				{ +					if(($value=$sm->validateData($value))!==false) +						$this->_cookies->add(new THttpCookie($key,$value)); +				} +			} +			else +			{ +				foreach($_COOKIE as $key=>$value) +					$this->_cookies->add(new THttpCookie($key,$value)); +			} +		} +		return $this->_cookies; +	} +	public function getUploadedFiles() +	{ +		return $_FILES; +	} +	public function getServerVariables() +	{ +		return $_SERVER; +	} +	public function getEnvironmentVariables() +	{ +		return $_ENV; +	} +	public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true) +	{ +		$url=$this->_urlManager->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems); +		if(defined('SID') && SID != '' && !$this->_cookieOnly) +			return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&':'&')) . SID; +		else +			return $url; +	} +	protected function parseUrl() +	{ +		return $this->_urlManager->parseUrl(); +	} +	public function resolveRequest($serviceIDs) +	{ +		$getParams=$this->parseUrl(); +		foreach($getParams as $name=>$value) +			$_GET[$name]=$value; +		$this->_items=array_merge($_GET,$_POST); +		$this->_requestResolved=true; +		foreach($serviceIDs as $serviceID) +		{ +			if($this->contains($serviceID)) +			{ +				$this->setServiceID($serviceID); +				$this->setServiceParameter($this->itemAt($serviceID)); +				return $serviceID; +			} +		} +		return null; +	} +	public function getRequestResolved() +	{ +		return $this->_requestResolved; +	} +	public function getServiceID() +	{ +		return $this->_serviceID; +	} +	public function setServiceID($value) +	{ +		$this->_serviceID=$value; +	} +	public function getServiceParameter() +	{ +		return $this->_serviceParam; +	} +	public function setServiceParameter($value) +	{ +		$this->_serviceParam=$value; +	} +	public function getIterator() +	{ +		return new TMapIterator($this->_items); +	} +	public function getCount() +	{ +		return count($this->_items); +	} +	public function count() +	{ +		return $this->getCount(); +	} +	public function getKeys() +	{ +		return array_keys($this->_items); +	} +	public function itemAt($key) +	{ +		return isset($this->_items[$key]) ? $this->_items[$key] : null; +	} +	public function add($key,$value) +	{ +		$this->_items[$key]=$value; +	} +	public function remove($key) +	{ +		if(isset($this->_items[$key]) || array_key_exists($key,$this->_items)) +		{ +			$value=$this->_items[$key]; +			unset($this->_items[$key]); +			return $value; +		} +		else +			return null; +	} +	public function clear() +	{ +		foreach(array_keys($this->_items) as $key) +			$this->remove($key); +	} +	public function contains($key) +	{ +		return isset($this->_items[$key]) || array_key_exists($key,$this->_items); +	} +	public function toArray() +	{ +		return $this->_items; +	} +	public function offsetExists($offset) +	{ +		return $this->contains($offset); +	} +	public function offsetGet($offset) +	{ +		return $this->itemAt($offset); +	} +	public function offsetSet($offset,$item) +	{ +		$this->add($offset,$item); +	} +	public function offsetUnset($offset) +	{ +		$this->remove($offset); +	} +} +class THttpCookieCollection extends TList +{ +	private $_o; +	public function __construct($owner=null) +	{ +		$this->_o=$owner; +	} +	public function insertAt($index,$item) +	{ +		if($item instanceof THttpCookie) +		{ +			parent::insertAt($index,$item); +			if($this->_o instanceof THttpResponse) +				$this->_o->addCookie($item); +		} +		else +			throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required'); +	} +	public function removeAt($index) +	{ +		$item=parent::removeAt($index); +		if($this->_o instanceof THttpResponse) +			$this->_o->removeCookie($item); +		return $item; +	} +	public function itemAt($index) +	{ +		if(is_integer($index)) +			return parent::itemAt($index); +		else +			return $this->findCookieByName($index); +	} +	public function findCookieByName($name) +	{ +		foreach($this as $cookie) +			if($cookie->getName()===$name) +				return $cookie; +		return null; +	} +} +class THttpCookie extends TComponent +{ +	private $_domain=''; +	private $_name; +	private $_value=''; +	private $_expire=0; +	private $_path='/'; +	private $_secure=false; +	public function __construct($name,$value) +	{ +		$this->_name=$name; +		$this->_value=$value; +	} +	public function getDomain() +	{ +		return $this->_domain; +	} +	public function setDomain($value) +	{ +		$this->_domain=$value; +	} +	public function getExpire() +	{ +		return $this->_expire; +	} +	public function setExpire($value) +	{ +		$this->_expire=TPropertyValue::ensureInteger($value); +	} +	public function getName() +	{ +		return $this->_name; +	} +	public function setName($value) +	{ +		$this->_name=$value; +	} +	public function getValue() +	{ +		return $this->_value; +	} +	public function setValue($value) +	{ +		$this->_value=$value; +	} +	public function getPath() +	{ +		return $this->_path; +	} +	public function setPath($value) +	{ +		$this->_path=$value; +	} +	public function getSecure() +	{ +		return $this->_secure; +	} +	public function setSecure($value) +	{ +		$this->_secure=TPropertyValue::ensureBoolean($value); +	} +} +class TUri extends TComponent +{ +	private static $_defaultPort=array( +		'ftp'=>21, +		'gopher'=>70, +		'http'=>80, +		'https'=>443, +		'news'=>119, +		'nntp'=>119, +		'wais'=>210, +		'telnet'=>23 +	); +	private $_scheme; +	private $_host; +	private $_port; +	private $_user; +	private $_pass; +	private $_path; +	private $_query; +	private $_fragment; +	private $_uri; +	public function __construct($uri) +	{ +		if(($ret=@parse_url($uri))!==false) +		{ +						$this->_scheme=isset($ret['scheme'])?$ret['scheme']:''; +			$this->_host=isset($ret['host'])?$ret['host']:''; +			$this->_port=isset($ret['port'])?$ret['port']:''; +			$this->_user=isset($ret['user'])?$ret['user']:''; +			$this->_pass=isset($ret['pass'])?$ret['pass']:''; +			$this->_path=isset($ret['path'])?$ret['path']:''; +			$this->_query=isset($ret['query'])?$ret['query']:''; +			$this->_fragment=isset($ret['fragment'])?$ret['fragment']:''; +			$this->_uri=$uri; +		} +		else +		{ +			throw new TInvalidDataValueException('uri_format_invalid',$uri); +		} +	} +	public function getUri() +	{ +		return $this->_uri; +	} +	public function getScheme() +	{ +		return $this->_scheme; +	} +	public function getHost() +	{ +		return $this->_host; +	} +	public function getPort() +	{ +		return $this->_port; +	} +	public function getUser() +	{ +		return $this->_user; +	} +	public function getPassword() +	{ +		return $this->_pass; +	} +	public function getPath() +	{ +		return $this->_path; +	} +	public function getQuery() +	{ +		return $this->_query; +	} +	public function getFragment() +	{ +		return $this->_fragment; +	} +} +class THttpRequestUrlFormat extends TEnumerable +{ +	const Get='Get'; +	const Path='Path'; +} +class THttpResponseAdapter extends TApplicationComponent +{ +	private $_response; +	public function __construct($response) +	{ +		$this->_response=$response; +	} +	public function getResponse() +	{ +		return $this->_response; +	} +	public function flushContent() +	{ +		$this->_response->flushContent(); +	} +	public function httpRedirect($url) +	{ +		$this->_response->httpRedirect($url); +	} +	public function createNewHtmlWriter($type, $writer) +	{ +		return $this->_response->createNewHtmlWriter($type,$writer); +	} +} +class THttpResponse extends TModule implements ITextWriter +{ +	private static $HTTP_STATUS_CODES = array( +		100 => 'Continue', 101 => 'Switching Protocols',  +		200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',  +		300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',  +		400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',  +		500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported' +	); +	private $_bufferOutput=true; +	private $_initialized=false; +	private $_cookies=null; +	private $_status=200; +	private $_reason='OK'; +	private $_htmlWriterType='System.Web.UI.THtmlWriter'; +	private $_contentType=null; +	private $_charset=''; +	private $_adapter; +	public function __destruct() +	{ +	} +	public function setAdapter(THttpResponseAdapter $adapter) +	{ +		$this->_adapter=$adapter; +	} +	public function getAdapter() +	{ +		return $this->_adapter; +	} +	public function getHasAdapter() +	{ +		return $this->_adapter!==null; +	} +	public function init($config) +	{ +		if($this->_bufferOutput) +			ob_start(); +		$this->_initialized=true; +		$this->getApplication()->setResponse($this); +	} +	public function getCacheExpire() +	{ +		return session_cache_expire(); +	} +	public function setCacheExpire($value) +	{ +		session_cache_expire(TPropertyValue::ensureInteger($value)); +	} +	public function getCacheControl() +	{ +		return session_cache_limiter(); +	} +	public function setCacheControl($value) +	{ +		session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public'))); +	} +	public function setContentType($type) +	{ +		$this->_contentType = $type; +	} +	public function getContentType() +	{ +		return $this->_contentType; +	} +	public function getCharset() +	{ +		return $this->_charset; +	} +	public function setCharset($charset) +	{ +		$this->_charset = $charset; +	} +	public function getBufferOutput() +	{ +		return $this->_bufferOutput; +	} +	public function setBufferOutput($value) +	{ +		if($this->_initialized) +			throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable'); +		else +			$this->_bufferOutput=TPropertyValue::ensureBoolean($value); +	} +	public function getStatusCode() +	{ +		return $this->_status; +	} +	public function setStatusCode($status, $reason=null) +	{ +		$status=TPropertyValue::ensureInteger($status); +		if(isset(self::$HTTP_STATUS_CODES[$status])) { +			$this->_reason=self::$HTTP_STATUS_CODES[$status]; +		}else{ +			if($reason===null || $reason==='') { +				throw new TInvalidDataValueException("response_status_reason_missing"); +			} +			$reason=TPropertyValue::ensureString($reason); +			if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) { +				throw new TInvalidDataValueException("response_status_reason_barchars"); +			} +			$this->_reason=$reason; +		} +		$this->_status=$status; +	} +	public function getStatusReason() { +		return $this->_reason; +	} +	public function getCookies() +	{ +		if($this->_cookies===null) +			$this->_cookies=new THttpCookieCollection($this); +		return $this->_cookies; +	} +	public function write($str) +	{ +		echo $str; +	} +	public function writeFile($fileName,$content=null,$mimeType=null,$headers=null) +	{ +		static $defaultMimeTypes=array( +			'css'=>'text/css', +			'gif'=>'image/gif', +			'jpg'=>'image/jpeg', +			'jpeg'=>'image/jpeg', +			'htm'=>'text/html', +			'html'=>'text/html', +			'js'=>'javascript/js', +			'pdf'=>'application/pdf', +			'xls'=>'application/vnd.ms-excel', +		); +		if($mimeType===null) +		{ +			$mimeType='text/plain'; +			if(function_exists('mime_content_type')) +				$mimeType=mime_content_type($fileName); +			else if(($ext=strrchr($fileName,'.'))!==false) +			{ +				$ext=substr($ext,1); +				if(isset($defaultMimeTypes[$ext])) +					$mimeType=$defaultMimeTypes[$ext]; +			} +		} +		$fn=basename($fileName); +		$this->sendHttpHeader(); +		if(is_array($headers)) +		{ +			foreach($headers as $h) +				header($h); +		} +		else +		{ +			header('Pragma: public'); +			header('Expires: 0'); +			header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); +		} +		header("Content-type: $mimeType"); +		header('Content-Length: '.($content===null?filesize($fileName):strlen($content))); +		header("Content-Disposition: attachment; filename=\"$fn\""); +		header('Content-Transfer-Encoding: binary'); +		if($content===null) +			readfile($fileName); +		else +			echo $content; +	} +	public function redirect($url) +	{ +		if($this->getHasAdapter()) +			$this->_adapter->httpRedirect($url); +		else +			$this->httpRedirect($url); +	} +	public function httpRedirect($url) +	{ +		if(!$this->getApplication()->getRequestCompleted()) +			$this->getApplication()->onEndRequest(); +		if($url[0]==='/') +			$url=$this->getRequest()->getBaseUrl().$url; +		if ($this->_status >= 300 && $this->_status < 400) +			header('Location: '.str_replace('&','&',$url), true, $this->_status); +		else +			header('Location: '.str_replace('&','&',$url)); +		exit(); +	} +	public function reload() +	{ +		$this->redirect($this->getRequest()->getRequestUri()); +	} +	public function flush() +	{ +		if($this->getHasAdapter()) +			$this->_adapter->flushContent(); +		else +			$this->flushContent(); +	} +	public function flushContent() +	{ +		$this->sendHttpHeader(); +		$this->sendContentTypeHeader(); +		if($this->_bufferOutput) +			ob_flush(); +	} +	protected function sendHttpHeader () +	{ +		if (($version=$this->getRequest()->getHttpProtocolVersion())==='') +			header (' ', true, $this->_status); +		else +			header($version.' '.$this->_status.' '.$this->_reason, true, $this->_status); +	} +	protected function sendContentTypeHeader() +	{ +		$charset=$this->getCharset(); +		if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null) +			$charset=$globalization->getCharset(); +		if($charset!=='') +		{ +			$contentType=$this->_contentType===null?'text/html':$this->_contentType; +			$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset); +		} +		else if($this->_contentType!==null) +			$this->appendHeader('Content-Type: '.$this->_contentType.';charset=UTF-8'); +	} +	public function getContents() +	{ +		return $this->_bufferOutput?ob_get_contents():''; +	} +	public function clear() +	{ +		if($this->_bufferOutput) +			ob_clean(); +	} +	public function appendHeader($value) +	{ +		header($value); +	} +	public function appendLog($message,$messageType=0,$destination='',$extraHeaders='') +	{ +		error_log($message,$messageType,$destination,$extraHeaders); +	} +	public function addCookie($cookie) +	{ +		$request=$this->getRequest(); +		if($request->getEnableCookieValidation()) +		{ +			$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue()); +			setcookie($cookie->getName(),$value,$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure()); +		} +		else +			setcookie($cookie->getName(),$cookie->getValue(),$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure()); +	} +	public function removeCookie($cookie) +	{ +		setcookie($cookie->getName(),null,0,$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure()); +	} +	public function getHtmlWriterType() +	{ +		return $this->_htmlWriterType; +	} +	public function setHtmlWriterType($value) +	{ +		$this->_htmlWriterType=$value; +	} +	public function createHtmlWriter($type=null) +	{ +		if($type===null) +			$type=$this->getHtmlWriterType(); +		if($this->getHasAdapter()) +			return $this->_adapter->createNewHtmlWriter($type, $this); +		else +		 	return $this->createNewHtmlWriter($type, $this); +	} +	public function createNewHtmlWriter($type, $writer) +	{ +		return Prado::createComponent($type, $writer); +	} +} +class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule +{ +	private $_initialized=false; +	private $_started=false; +	private $_autoStart=false; +	private $_cookie=null; +	private $_id; +	private $_customStorage=false; +	public function getID() +	{ +		return $this->_id; +	} +	public function setID($value) +	{ +		$this->_id=$value; +	} +	public function init($config) +	{ +		if($this->_autoStart) +			$this->open(); +		$this->_initialized=true; +		$this->getApplication()->setSession($this); +		register_shutdown_function(array($this, "close")); +	} +	public function open() +	{ +		if(!$this->_started) +		{ +			if($this->_customStorage) +				session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc')); +			if($this->_cookie!==null) +				session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure()); +			if(ini_get('session.auto_start')!=='1') +				session_start(); +			$this->_started=true; +		} +	} +	public function close() +	{ +		if($this->_started) +		{ +			session_write_close(); +			$this->_started=false; +		} +	} +	public function destroy() +	{ +		if($this->_started) +		{ +			session_destroy(); +			$this->_started=false; +		} +	} +	public function getIsStarted() +	{ +		return $this->_started; +	} +	public function getSessionID() +	{ +		return session_id(); +	} +	public function setSessionID($value) +	{ +		if($this->_started) +			throw new TInvalidOperationException('httpsession_sessionid_unchangeable'); +		else +			session_id($value); +	} +	public function getSessionName() +	{ +		return session_name(); +	} +	public function setSessionName($value) +	{ +		if($this->_started) +			throw new TInvalidOperationException('httpsession_sessionname_unchangeable'); +		else if(ctype_alnum($value)) +			session_name($value); +		else +			throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value); +	} +	public function getSavePath() +	{ +		return session_save_path(); +	} +	public function setSavePath($value) +	{ +		if($this->_started) +			throw new TInvalidOperationException('httpsession_savepath_unchangeable'); +		else if(is_dir($value)) +			session_save_path($value); +		else +			throw new TInvalidDataValueException('httpsession_savepath_invalid',$value); +	} +	public function getUseCustomStorage() +	{ +		return $this->_customStorage; +	} +	public function setUseCustomStorage($value) +	{ +		$this->_customStorage=TPropertyValue::ensureBoolean($value); +	} +	public function getCookie() +	{ +		if($this->_cookie===null) +			$this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID()); +		return $this->_cookie; +	} +	public function getCookieMode() +	{ +		if(ini_get('session.use_cookies')==='0') +			return THttpSessionCookieMode::None; +		else if(ini_get('session.use_only_cookies')==='0') +			return THttpSessionCookieMode::Allow; +		else +			return THttpSessionCookieMode::Only; +	} +	public function setCookieMode($value) +	{ +		if($this->_started) +			throw new TInvalidOperationException('httpsession_cookiemode_unchangeable'); +		else +		{ +			$value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode'); +			if($value===THttpSessionCookieMode::None) +				ini_set('session.use_cookies','0'); +			else if($value===THttpSessionCookieMode::Allow) +			{ +				ini_set('session.use_cookies','1'); +				ini_set('session.use_only_cookies','0'); +			} +			else +			{ +				ini_set('session.use_cookies','1'); +				ini_set('session.use_only_cookies','1'); +			} +		} +	} +	public function getAutoStart() +	{ +		return $this->_autoStart; +	} +	public function setAutoStart($value) +	{ +		if($this->_initialized) +			throw new TInvalidOperationException('httpsession_autostart_unchangeable'); +		else +			$this->_autoStart=TPropertyValue::ensureBoolean($value); +	} +	public function getGCProbability() +	{ +		return TPropertyValue::ensureInteger(ini_get('session.gc_probability')); +	} +	public function setGCProbability($value) +	{ +		if($this->_started) +			throw new TInvalidOperationException('httpsession_gcprobability_unchangeable'); +		else +		{ +			$value=TPropertyValue::ensureInteger($value); +			if($value>=0 && $value<=100) +			{ +				ini_set('session.gc_probability',$value); +				ini_set('session.gc_divisor','100'); +			} +			else +				throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value); +		} +	} +	public function getUseTransparentSessionID() +	{ +		return ini_get('session.use_trans_sid')==='1'; +	} +	public function setUseTransparentSessionID($value) +	{ +		if($this->_started) +			throw new TInvalidOperationException('httpsession_transid_unchangeable'); +		else +			ini_set('session.use_trans_sid',TPropertyValue::ensureBoolean($value)?'1':'0'); +	} +	public function getTimeout() +	{ +		return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime')); +	} +	public function setTimeout($value) +	{ +		if($this->_started) +			throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable'); +		else +			ini_set('session.gc_maxlifetime',$value); +	} +	public function _open($savePath,$sessionName) +	{ +		return true; +	} +	public function _close() +	{ +		return true; +	} +	public function _read($id) +	{ +		return ''; +	} +	public function _write($id,$data) +	{ +		return true; +	} +	public function _destroy($id) +	{ +		return true; +	} +	public function _gc($maxLifetime) +	{ +		return true; +	} +	public function getIterator() +	{ +		return new TSessionIterator; +	} +	public function getCount() +	{ +		return count($_SESSION); +	} +	public function count() +	{ +		return $this->getCount(); +	} +	public function getKeys() +	{ +		return array_keys($_SESSION); +	} +	public function itemAt($key) +	{ +		return isset($_SESSION[$key]) ? $_SESSION[$key] : null; +	} +	public function add($key,$value) +	{ +		$_SESSION[$key]=$value; +	} +	public function remove($key) +	{ +		if(isset($_SESSION[$key])) +		{ +			$value=$_SESSION[$key]; +			unset($_SESSION[$key]); +			return $value; +		} +		else +			return null; +	} +	public function clear() +	{ +		foreach(array_keys($_SESSION) as $key) +			unset($_SESSION[$key]); +	} +	public function contains($key) +	{ +		return isset($_SESSION[$key]); +	} +	public function toArray() +	{ +		return $_SESSION; +	} +	public function offsetExists($offset) +	{ +		return isset($_SESSION[$offset]); +	} +	public function offsetGet($offset) +	{ +		return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null; +	} +	public function offsetSet($offset,$item) +	{ +		$_SESSION[$offset]=$item; +	} +	public function offsetUnset($offset) +	{ +		unset($_SESSION[$offset]); +	} +} +class TSessionIterator implements Iterator +{ +	private $_keys; +	private $_key; +	public function __construct() +	{ +		$this->_keys=array_keys($_SESSION); +	} +	public function rewind() +	{ +		$this->_key=reset($this->_keys); +	} +	public function key() +	{ +		return $this->_key; +	} +	public function current() +	{ +		return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null; +	} +	public function next() +	{ +		do +		{ +			$this->_key=next($this->_keys); +		} +		while(!isset($_SESSION[$this->_key]) && $this->_key!==false); +	} +	public function valid() +	{ +		return $this->_key!==false; +	} +} +class THttpSessionCookieMode extends TEnumerable +{ +	const None='None'; +	const Allow='Allow'; +	const Only='Only'; +} +Prado::using('System.Web.UI.WebControls.*'); +class TAttributeCollection extends TMap +{ +	private $_caseSensitive=false; +	public function __get($name) +	{ +		return $this->contains($name)?$this->itemAt($name):parent::__get($name); +	} +	public function __set($name,$value) +	{ +		$this->add($name,$value); +	} +	public function getCaseSensitive() +	{ +		return $this->_caseSensitive; +	} +	public function setCaseSensitive($value) +	{ +		$this->_caseSensitive=TPropertyValue::ensureBoolean($value); +	} +	public function itemAt($key) +	{ +		return parent::itemAt($this->_caseSensitive?$key:strtolower($key)); +	} +	public function add($key,$value) +	{ +		parent::add($this->_caseSensitive?$key:strtolower($key),$value); +	} +	public function remove($key) +	{ +		return parent::remove($this->_caseSensitive?$key:strtolower($key)); +	} +	public function contains($key) +	{ +		return parent::contains($this->_caseSensitive?$key:strtolower($key)); +	} +	public function hasProperty($name) +	{ +		return $this->contains($name) || parent::hasProperty($name); +	} +	public function canGetProperty($name) +	{ +		return $this->contains($name) || parent::canGetProperty($name); +	} +	public function canSetProperty($name) +	{ +		return true; +	} +} +class TControlAdapter extends TApplicationComponent +{ +	private $_control; +	public function __construct($control) +	{ +		$this->_control=$control; +	} +	public function getControl() +	{ +		return $this->_control; +	} +	public function getPage() +	{ +		return $this->_control?$this->_control->getPage():null; +	} +	public function createChildControls() +	{ +		$this->_control->createChildControls(); +	} +	public function loadState() +	{ +		$this->_control->loadState(); +	} +	public function saveState() +	{ +		$this->_control->saveState(); +	} +	public function onInit($param) +	{ +		$this->_control->onInit($param); +	} +	public function onLoad($param) +	{ +		$this->_control->onLoad($param); +	} +	public function onPreRender($param) +	{ +		$this->_control->onPreRender($param); +	} +	public function onUnload($param) +	{ +		$this->_control->onUnload($param); +	} +	public function render($writer) +	{ +		$this->_control->render($writer); +	} +	public function renderChildren($writer) +	{ +		$this->_control->renderChildren($writer); +	} +} +class TControl extends TApplicationComponent implements IRenderable, IBindable +{ +	const ID_FORMAT='/^[a-zA-Z_]\\w*$/'; +	const ID_SEPARATOR='$'; +	const CLIENT_ID_SEPARATOR='_'; +	const AUTOMATIC_ID_PREFIX='ctl'; +	const CS_CONSTRUCTED=0; +	const CS_CHILD_INITIALIZED=1; +	const CS_INITIALIZED=2; +	const CS_STATE_LOADED=3; +	const CS_LOADED=4; +	const CS_PRERENDERED=5; +	const IS_ID_SET=0x01; +	const IS_DISABLE_VIEWSTATE=0x02; +	const IS_SKIN_APPLIED=0x04; +	const IS_STYLESHEET_APPLIED=0x08; +	const IS_DISABLE_THEMING=0x10; +	const IS_CHILD_CREATED=0x20; +	const IS_CREATING_CHILD=0x40; +	const RF_CONTROLS=0;			 +	const RF_CHILD_STATE=1;			 +	const RF_NAMED_CONTROLS=2;		 +	const RF_NAMED_CONTROLS_ID=3;	 +	const RF_SKIN_ID=4;				 +	const RF_DATA_BINDINGS=5;		 +	const RF_EVENTS=6;				 +	const RF_CONTROLSTATE=7;		 +	const RF_NAMED_OBJECTS=8;		 +	const RF_ADAPTER=9;				 +	const RF_AUTO_BINDINGS=10;		 +	private $_id=''; +	private $_uid; +	private $_parent; +	private $_page; +	private $_namingContainer; +	private $_tplControl; +	private $_viewState=array(); +	private $_tempState=array(); +	private $_trackViewState=true; +	private $_stage=0; +	private $_flags=0; +	private $_rf=array(); +	public function __construct() +	{ +	} +	public function __get($name) +	{ +		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) +			return $this->_rf[self::RF_NAMED_OBJECTS][$name]; +		else +			return parent::__get($name); +	} +	public function getHasAdapter() +	{ +		return isset($this->_rf[self::RF_ADAPTER]); +	} +	public function getAdapter() +	{ +		return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null; +	} +	public function setAdapter(TControlAdapter $adapter) +	{ +		$this->_rf[self::RF_ADAPTER]=$adapter; +	} +	public function getParent() +	{ +		return $this->_parent; +	} +	public function getNamingContainer() +	{ +		if(!$this->_namingContainer && $this->_parent) +		{ +			if($this->_parent instanceof INamingContainer) +				$this->_namingContainer=$this->_parent; +			else +				$this->_namingContainer=$this->_parent->getNamingContainer(); +		} +		return $this->_namingContainer; +	} +	public function getPage() +	{ +		if(!$this->_page) +		{ +			if($this->_parent) +				$this->_page=$this->_parent->getPage(); +			else if($this->_tplControl) +				$this->_page=$this->_tplControl->getPage(); +		} +		return $this->_page; +	} +	public function setPage($page) +	{ +		$this->_page=$page; +	} +	public function setTemplateControl($control) +	{ +		$this->_tplControl=$control; +	} +	public function getTemplateControl() +	{ +		if(!$this->_tplControl && $this->_parent) +			$this->_tplControl=$this->_parent->getTemplateControl(); +		return $this->_tplControl; +	} +	public function getSourceTemplateControl() +	{ +		$control=$this; +		while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null) +		{ +			if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl()) +				return $control; +		} +		return $this->getPage(); +	} +	protected function getControlStage() +	{ +		return $this->_stage; +	} +	protected function setControlStage($value) +	{ +		$this->_stage=$value; +	} +	public function getID($hideAutoID=true) +	{ +		if($hideAutoID) +			return ($this->_flags & self::IS_ID_SET) ? $this->_id : ''; +		else +			return $this->_id; +	} +	public function setID($id) +	{ +		if(!preg_match(self::ID_FORMAT,$id)) +			throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id); +		$this->_id=$id; +		$this->_flags |= self::IS_ID_SET; +		$this->clearCachedUniqueID($this instanceof INamingContainer); +		if($this->_namingContainer) +			$this->_namingContainer->clearNameTable(); +	} +	public function getUniqueID() +	{ +		if($this->_uid==='' || $this->_uid===null)	 +		{ +			$this->_uid='';   +			if($namingContainer=$this->getNamingContainer()) +			{ +				if($this->getPage()===$namingContainer) +					return ($this->_uid=$this->_id); +				else if(($prefix=$namingContainer->getUniqueID())==='') +					return $this->_id; +				else +					return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id); +			} +			else	 +				return $this->_id; +		} +		else +			return $this->_uid; +	} +	public function focus() +	{ +		$this->getPage()->setFocus($this); +	} +	public function getClientID() +	{ +		return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR); +	} +	public static function convertUniqueIdToClientId($uniqueID) +	{ +		return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR); +	} +	public function getSkinID() +	{ +		return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:''; +	} +	public function setSkinID($value) +	{ +		if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED) +			throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this)); +		else +			$this->_rf[self::RF_SKIN_ID]=$value; +	} +	public function getEnableTheming() +	{ +		if($this->_flags & self::IS_DISABLE_THEMING) +			return false; +		else +			return $this->_parent?$this->_parent->getEnableTheming():true; +	} +	public function setEnableTheming($value) +	{ +		if($this->_stage>=self::CS_CHILD_INITIALIZED) +			throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID()); +		else if(TPropertyValue::ensureBoolean($value)) +			$this->_flags &= ~self::IS_DISABLE_THEMING; +		else +			$this->_flags |= self::IS_DISABLE_THEMING; +	} +	public function getCustomData() +	{ +		return $this->getViewState('CustomData',null); +	} +	public function setCustomData($value) +	{ +		$this->setViewState('CustomData',$value,null); +	} +	public function getHasControls() +	{ +		return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0; +	} +	public function getControls() +	{ +		if(!isset($this->_rf[self::RF_CONTROLS])) +			$this->_rf[self::RF_CONTROLS]=$this->createControlCollection(); +		return $this->_rf[self::RF_CONTROLS]; +	} +	protected function createControlCollection() +	{ +		return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this); +	} +	public function getVisible($checkParents=true) +	{ +		if($checkParents) +		{ +			for($control=$this;$control;$control=$control->_parent) +				if(!$control->getVisible(false)) +					return false; +			return true; +		} +		else +			return $this->getViewState('Visible',true); +	} +	public function setVisible($value) +	{ +		$this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true); +	} +	public function getEnabled($checkParents=false) +	{ +		if($checkParents) +		{ +			for($control=$this;$control;$control=$control->_parent) +				if(!$control->getViewState('Enabled',true)) +					return false; +			return true; +		} +		else +			return $this->getViewState('Enabled',true); +	} +	public function setEnabled($value) +	{ +		$this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true); +	} +	public function getHasAttributes() +	{ +		if($attributes=$this->getViewState('Attributes',null)) +			return $attributes->getCount()>0; +		else +			return false; +	} +	public function getAttributes() +	{ +		if($attributes=$this->getViewState('Attributes',null)) +			return $attributes; +		else +		{ +			$attributes=new TAttributeCollection; +			$this->setViewState('Attributes',$attributes,null); +			return $attributes; +		} +	} +	public function hasAttribute($name) +	{ +		if($attributes=$this->getViewState('Attributes',null)) +			return $attributes->contains($name); +		else +			return false; +	} +	public function getAttribute($name) +	{ +		if($attributes=$this->getViewState('Attributes',null)) +			return $attributes->itemAt($name); +		else +			return null; +	} +	public function setAttribute($name,$value) +	{ +		$this->getAttributes()->add($name,$value); +	} +	public function removeAttribute($name) +	{ +		if($attributes=$this->getViewState('Attributes',null)) +			return $attributes->remove($name); +		else +			return null; +	} +	public function getEnableViewState($checkParents=false) +	{ +		if($checkParents) +		{ +			for($control=$this;$control!==null;$control=$control->getParent()) +				if($control->_flags & self::IS_DISABLE_VIEWSTATE) +					return false; +			return true; +		} +		else +			return !($this->_flags & self::IS_DISABLE_VIEWSTATE); +	} +	public function setEnableViewState($value) +	{ +		if(TPropertyValue::ensureBoolean($value)) +			$this->_flags &= ~self::IS_DISABLE_VIEWSTATE; +		else +			$this->_flags |= self::IS_DISABLE_VIEWSTATE; +	} +	protected function getControlState($key,$defaultValue=null) +	{ +		return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue; +	} +	protected function setControlState($key,$value,$defaultValue=null) +	{ +		if($value===$defaultValue) +			unset($this->_rf[self::RF_CONTROLSTATE][$key]); +		else +			$this->_rf[self::RF_CONTROLSTATE][$key]=$value; +	} +	protected function clearControlState($key) +	{ +		unset($this->_rf[self::RF_CONTROLSTATE][$key]); +	} +	public function trackViewState($enabled) +	{ +		$this->_trackViewState=TPropertyValue::ensureBoolean($enabled); +	} +	public function getViewState($key,$defaultValue=null) +	{ +		if(isset($this->_viewState[$key])) +			return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue; +		else if(isset($this->_tempState[$key])) +		{ +			if(is_object($this->_tempState[$key]) && $this->_trackViewState) +				$this->_viewState[$key]=$this->_tempState[$key]; +			return $this->_tempState[$key]; +		} +		else +			return $defaultValue; +	} +	public function setViewState($key,$value,$defaultValue=null) +	{ +		if($this->_trackViewState) +		{ +			$this->_viewState[$key]=$value; +			unset($this->_tempState[$key]); +		} +		else +		{ +			unset($this->_viewState[$key]); +			$this->_tempState[$key]=$value; +		} +	} +	public function clearViewState($key) +	{ +		unset($this->_viewState[$key]); +		unset($this->_tempState[$key]); +	} +	public function bindProperty($name,$expression) +	{ +		$this->_rf[self::RF_DATA_BINDINGS][$name]=$expression; +	} +	public function unbindProperty($name) +	{ +		unset($this->_rf[self::RF_DATA_BINDINGS][$name]); +	} +	public function autoBindProperty($name,$expression) +	{ +		$this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression; +	} +	public function dataBind() +	{ +		$this->dataBindProperties(); +		$this->onDataBinding(null); +		$this->dataBindChildren(); +	} +	protected function dataBindProperties() +	{ +		if(isset($this->_rf[self::RF_DATA_BINDINGS])) +		{ +			if(($context=$this->getTemplateControl())===null) +				$context=$this; +			foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression) +				$this->setSubProperty($property,$context->evaluateExpression($expression)); +		} +	} +	protected function autoDataBindProperties() +	{ +		if(isset($this->_rf[self::RF_AUTO_BINDINGS])) +		{ +			if(($context=$this->getTemplateControl())===null) +				$context=$this; +			foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression) +				$this->setSubProperty($property,$context->evaluateExpression($expression)); +		} +	} +	protected function dataBindChildren() +	{ +		if(isset($this->_rf[self::RF_CONTROLS])) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +				if($control instanceof IBindable) +					$control->dataBind(); +		} +	} +	final protected function getChildControlsCreated() +	{ +		return ($this->_flags & self::IS_CHILD_CREATED)!==0; +	} +	final protected function setChildControlsCreated($value) +	{ +		if($value) +			$this->_flags |= self::IS_CHILD_CREATED; +		else +		{ +			if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED)) +				$this->getControls()->clear(); +			$this->_flags &= ~self::IS_CHILD_CREATED; +		} +	} +	public function ensureChildControls() +	{ +		if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD)) +		{ +			try +			{ +				$this->_flags |= self::IS_CREATING_CHILD; +				if(isset($this->_rf[self::RF_ADAPTER])) +					$this->_rf[self::RF_ADAPTER]->createChildControls(); +				else +					$this->createChildControls(); +				$this->_flags &= ~self::IS_CREATING_CHILD; +				$this->_flags |= self::IS_CHILD_CREATED; +			} +			catch(Exception $e) +			{ +				$this->_flags &= ~self::IS_CREATING_CHILD; +				$this->_flags |= self::IS_CHILD_CREATED; +				throw $e; +			} +		} +	} +	public function createChildControls() +	{ +	} +	public function findControl($id) +	{ +		$id=strtr($id,'.',self::ID_SEPARATOR); +		$container=($this instanceof INamingContainer)?$this:$this->getNamingContainer(); +		if(!$container || !$container->getHasControls()) +			return null; +		if(!isset($container->_rf[self::RF_NAMED_CONTROLS])) +		{ +			$container->_rf[self::RF_NAMED_CONTROLS]=array(); +			$container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]); +		} +		if(($pos=strpos($id,self::ID_SEPARATOR))===false) +			return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null; +		else +		{ +			$cid=substr($id,0,$pos); +			$sid=substr($id,$pos+1); +			if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid])) +				return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid); +			else +				return null; +		} +	} +	public function findControlsByType($type,$strict=true) +	{ +		$controls=array(); +		if($this->getHasControls()) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +			{ +				if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type)))) +					$controls[]=$control; +				if(($control instanceof TControl) && $control->getHasControls()) +					$controls=array_merge($controls,$control->findControlsByType($type,$strict)); +			} +		} +		return $controls; +	} +	public function findControlsByID($id) +	{ +		$controls=array(); +		if($this->getHasControls()) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +			{ +				if($control instanceof TControl) +				{ +					if($control->_id===$id) +						$controls[]=$control; +					$controls=array_merge($controls,$control->findControlsByID($id)); +				} +			} +		} +		return $controls; +	} +	public function clearNamingContainer() +	{ +		unset($this->_rf[self::RF_NAMED_CONTROLS_ID]); +		$this->clearNameTable(); +	} +	public function registerObject($name,$object) +	{ +		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) +			throw new TInvalidOperationException('control_object_reregistered',$name); +		$this->_rf[self::RF_NAMED_OBJECTS][$name]=$object; +	} +	public function unregisterObject($name) +	{ +		unset($this->_rf[self::RF_NAMED_OBJECTS][$name]); +	} +	public function isObjectRegistered($name) +	{ +		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]); +	} +	public function getHasChildInitialized() +	{ +		return $this->getControlStage() >= self::CS_CHILD_INITIALIZED; +	} +	public function getHasInitialized() +	{ +		return $this->getControlStage() >= self::CS_INITIALIZED; +	} +	public function getHasLoadedPostData() +	{ +		return $this->getControlStage() >= self::CS_STATE_LOADED; +	} +	public function getHasLoaded() +	{ +		return $this->getControlStage() >= self::CS_LOADED; +	} +	public function getHasPreRendered() +	{ +		return $this->getControlStage() >= self::CS_PRERENDERED; +	} +	public function getRegisteredObject($name) +	{ +		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null; +	} +	public function getAllowChildControls() +	{ +		return true; +	} +	public function addParsedObject($object) +	{ +		$this->getControls()->add($object); +	} +	final protected function clearChildState() +	{ +		unset($this->_rf[self::RF_CHILD_STATE]); +	} +	final protected function isDescendentOf($ancestor) +	{ +		$control=$this; +		while($control!==$ancestor && $control->_parent) +			$control=$control->_parent; +		return $control===$ancestor; +	} +	public function addedControl($control) +	{ +		if($control->_parent) +			$control->_parent->getControls()->remove($control); +		$control->_parent=$this; +		$control->_page=$this->getPage(); +		$namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer; +		if($namingContainer) +		{ +			$control->_namingContainer=$namingContainer; +			if($control->_id==='') +				$control->generateAutomaticID(); +			else +				$namingContainer->clearNameTable(); +			$control->clearCachedUniqueID($control instanceof INamingContainer); +		} +		if($this->_stage>=self::CS_CHILD_INITIALIZED) +		{ +			$control->initRecursive($namingContainer); +			if($this->_stage>=self::CS_STATE_LOADED) +			{ +				if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id])) +				{ +					$state=$this->_rf[self::RF_CHILD_STATE][$control->_id]; +					unset($this->_rf[self::RF_CHILD_STATE][$control->_id]); +				} +				else +					$state=null; +				$control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE)); +				if($this->_stage>=self::CS_LOADED) +				{ +					$control->loadRecursive(); +					if($this->_stage>=self::CS_PRERENDERED) +						$control->preRenderRecursive(); +				} +			} +		} +	} +	public function removedControl($control) +	{ +		if($this->_namingContainer) +			$this->_namingContainer->clearNameTable(); +		$control->unloadRecursive(); +		$control->_parent=null; +		$control->_page=null; +		$control->_namingContainer=null; +		$control->_tplControl=null; +		if(!($control->_flags & self::IS_ID_SET)) +			$control->_id=''; +		else +			unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]); +		$control->clearCachedUniqueID(true); +	} +	protected function initRecursive($namingContainer=null) +	{ +		$this->ensureChildControls(); +		if($this->getHasControls()) +		{ +			if($this instanceof INamingContainer) +				$namingContainer=$this; +			$page=$this->getPage(); +			foreach($this->_rf[self::RF_CONTROLS] as $control) +			{ +				if($control instanceof TControl) +				{ +					$control->_namingContainer=$namingContainer; +					$control->_page=$page; +					if($control->_id==='' && $namingContainer) +						$control->generateAutomaticID(); +					$control->initRecursive($namingContainer); +				} +			} +		} +		if($this->_stage<self::CS_INITIALIZED) +		{ +			$this->_stage=self::CS_CHILD_INITIALIZED; +			if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED)) +			{ +				$page->applyControlSkin($this); +				$this->_flags |= self::IS_SKIN_APPLIED; +			} +			if(isset($this->_rf[self::RF_ADAPTER])) +				$this->_rf[self::RF_ADAPTER]->onInit(null); +			else +				$this->onInit(null); +			$this->_stage=self::CS_INITIALIZED; +		} +	} +	protected function loadRecursive() +	{ +		if($this->_stage<self::CS_LOADED) +		{ +			if(isset($this->_rf[self::RF_ADAPTER])) +				$this->_rf[self::RF_ADAPTER]->onLoad(null); +			else +				$this->onLoad(null); +		} +		if($this->getHasControls()) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +			{ +				if($control instanceof TControl) +					$control->loadRecursive(); +			} +		} +		if($this->_stage<self::CS_LOADED) +			$this->_stage=self::CS_LOADED; +	} +	protected function preRenderRecursive() +	{ +		$this->autoDataBindProperties(); +		if($this->getVisible(false)) +		{ +			if(isset($this->_rf[self::RF_ADAPTER])) +				$this->_rf[self::RF_ADAPTER]->onPreRender(null); +			else +				$this->onPreRender(null); +			if($this->getHasControls()) +			{ +				foreach($this->_rf[self::RF_CONTROLS] as $control) +				{ +					if($control instanceof TControl) +						$control->preRenderRecursive(); +					else if($control instanceof TCompositeLiteral) +						$control->evaluateDynamicContent(); +				} +			} +			$this->addToPostDataLoader(); +		} +		$this->_stage=self::CS_PRERENDERED; +	} +	protected function addToPostDataLoader() +	{ +		if($this instanceof IPostBackDataHandler) +			$this->getPage()->registerPostDataLoader($this); +	} +	protected function unloadRecursive() +	{ +		if(!($this->_flags & self::IS_ID_SET)) +			$this->_id=''; +		if($this->getHasControls()) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +				if($control instanceof TControl) +					$control->unloadRecursive(); +		} +		if(isset($this->_rf[self::RF_ADAPTER])) +			$this->_rf[self::RF_ADAPTER]->onUnload(null); +		else +			$this->onUnload(null); +	} +	public function onInit($param) +	{ +		$this->raiseEvent('OnInit',$this,$param); +	} +	public function onLoad($param) +	{ +		$this->raiseEvent('OnLoad',$this,$param); +	} +	public function onDataBinding($param) +	{ +		$this->raiseEvent('OnDataBinding',$this,$param); +	} +	public function onUnload($param) +	{ +		$this->raiseEvent('OnUnload',$this,$param); +	} +	public function onPreRender($param) +	{ +		$this->raiseEvent('OnPreRender',$this,$param); +	} +	protected function raiseBubbleEvent($sender,$param) +	{ +		$control=$this; +		while($control=$control->_parent) +		{ +			if($control->bubbleEvent($sender,$param)) +				break; +		} +	} +	public function bubbleEvent($sender,$param) +	{ +		return false; +	} +	public function broadcastEvent($name,$sender,$param) +	{ +		$rootControl=(($page=$this->getPage())===null)?$this:$page; +		$rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param)); +	} +	private function broadcastEventInternal($name,$sender,$param) +	{ +		if($this->hasEvent($name)) +			$this->raiseEvent($name,$sender,$param->getParameter()); +		if($this instanceof IBroadcastEventReceiver) +			$this->broadcastEventReceived($sender,$param); +		if($this->getHasControls()) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +			{ +				if($control instanceof TControl) +					$control->broadcastEventInternal($name,$sender,$param); +			} +		} +	} +	protected function traverseChildControls($param,$preCallback=null,$postCallback=null) +	{ +		if($preCallback!==null) +			call_user_func($preCallback,$this,$param); +		if($this->getHasControls()) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +			{ +				if($control instanceof TControl) +				{ +					$control->traverseChildControls($param,$preCallback,$postCallback); +				} +			} +		} +		if($postCallback!==null) +			call_user_func($postCallback,$this,$param); +	} +	public function renderControl($writer) +	{ +		if($this->getVisible(false)) +		{ +			if(isset($this->_rf[self::RF_ADAPTER])) +				$this->_rf[self::RF_ADAPTER]->render($writer); +			else +				$this->render($writer); +		} +	} +	public function render($writer) +	{ +		$this->renderChildren($writer); +	} +	public function renderChildren($writer) +	{ +		if($this->getHasControls()) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +			{ +				if(is_string($control)) +					$writer->write($control); +				else if($control instanceof TControl) +					$control->renderControl($writer); +				else if($control instanceof IRenderable) +					$control->render($writer); +			} +		} +	} +	public function saveState() +	{ +	} +	public function loadState() +	{ +	} +	protected function loadStateRecursive(&$state,$needViewState=true) +	{ +		if(is_array($state)) +		{ +			$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE)); +			if(isset($state[1])) +			{ +				$this->_rf[self::RF_CONTROLSTATE]=&$state[1]; +				unset($state[1]); +			} +			else +				unset($this->_rf[self::RF_CONTROLSTATE]); +			if($needViewState) +			{ +				if(isset($state[0])) +					$this->_viewState=&$state[0]; +				else +					$this->_viewState=array(); +			} +			unset($state[0]); +			if($this->getHasControls()) +			{ +				foreach($this->_rf[self::RF_CONTROLS] as $control) +				{ +					if($control instanceof TControl) +					{ +						if(isset($state[$control->_id])) +						{ +							$control->loadStateRecursive($state[$control->_id],$needViewState); +							unset($state[$control->_id]); +						} +					} +				} +			} +			if(!empty($state)) +				$this->_rf[self::RF_CHILD_STATE]=&$state; +		} +		$this->_stage=self::CS_STATE_LOADED; +		if(isset($this->_rf[self::RF_ADAPTER])) +			$this->_rf[self::RF_ADAPTER]->loadState(); +		else +			$this->loadState(); +	} +	protected function &saveStateRecursive($needViewState=true) +	{ +		if(isset($this->_rf[self::RF_ADAPTER])) +			$this->_rf[self::RF_ADAPTER]->saveState(); +		else +			$this->saveState(); +		$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE)); +		$state=array(); +		if($this->getHasControls()) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +			{ +				if($control instanceof TControl) +					$state[$control->_id]=&$control->saveStateRecursive($needViewState); +			} +		} +		if($needViewState && !empty($this->_viewState)) +			$state[0]=&$this->_viewState; +		if(isset($this->_rf[self::RF_CONTROLSTATE])) +			$state[1]=&$this->_rf[self::RF_CONTROLSTATE]; +		return $state; +	} +	public function applyStyleSheetSkin($page) +	{ +		if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED)) +		{ +			$page->applyControlStyleSheet($this); +			$this->_flags |= self::IS_STYLESHEET_APPLIED; +		} +		else if($this->_flags & self::IS_STYLESHEET_APPLIED) +			throw new TInvalidOperationException('control_stylesheet_applied',get_class($this)); +	} +	private function clearCachedUniqueID($recursive) +	{ +		if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS])) +		{ +			foreach($this->_rf[self::RF_CONTROLS] as $control) +				if($control instanceof TControl) +					$control->clearCachedUniqueID($recursive); +		} +		$this->_uid=null; +	} +	private function generateAutomaticID() +	{ +		$this->_flags &= ~self::IS_ID_SET; +		if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID])) +			$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0; +		$id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++; +		$this->_id=self::AUTOMATIC_ID_PREFIX . $id; +		$this->_namingContainer->clearNameTable(); +	} +	private function clearNameTable() +	{ +		unset($this->_rf[self::RF_NAMED_CONTROLS]); +	} +	private function fillNameTable($container,$controls) +	{ +		foreach($controls as $control) +		{ +			if($control instanceof TControl) +			{ +				if($control->_id!=='') +				{ +					if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id])) +						throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id); +					else +						$container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control; +				} +				if(!($control instanceof INamingContainer) && $control->getHasControls()) +					$this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]); +			} +		} +	} +} +class TControlCollection extends TList +{ +	private $_o; +	public function __construct(TControl $owner,$readOnly=false) +	{ +		$this->_o=$owner; +		parent::__construct(null,$readOnly); +	} +	protected function getOwner() +	{ +		return $this->_o; +	} +	public function insertAt($index,$item) +	{ +		if($item instanceof TControl) +		{ +			parent::insertAt($index,$item); +			$this->_o->addedControl($item); +		} +		else if(is_string($item) || ($item instanceof IRenderable)) +			parent::insertAt($index,$item); +		else +			throw new TInvalidDataTypeException('controlcollection_control_required'); +	} +	public function removeAt($index) +	{ +		$item=parent::removeAt($index); +		if($item instanceof TControl) +			$this->_o->removedControl($item); +		return $item; +	} +	public function clear() +	{ +		parent::clear(); +		if($this->_o instanceof INamingContainer) +			$this->_o->clearNamingContainer(); +	} +} +class TEmptyControlCollection extends TControlCollection +{ +	public function __construct(TControl $owner) +	{ +		parent::__construct($owner,true); +	} +	public function insertAt($index,$item) +	{ +		if(!is_string($item))   +			parent::insertAt($index,$item);   +	} +} +interface INamingContainer +{ +} +interface IPostBackEventHandler +{ +	public function raisePostBackEvent($param); +} +interface IPostBackDataHandler +{ +	public function loadPostData($key,$values); +	public function raisePostDataChangedEvent(); +	public function getDataChanged(); +} +interface IValidator +{ +	public function validate(); +	public function getIsValid(); +	public function setIsValid($value); +	public function getErrorMessage(); +	public function setErrorMessage($value); +} +interface IValidatable +{ +	public function getValidationPropertyValue(); +	public function getIsValid(); +	public function setIsValid($value); +} +interface IBroadcastEventReceiver +{ +	public function broadcastEventReceived($sender,$param); +} +interface ITheme +{ +	public function applySkin($control); +} +interface ITemplate +{ +	public function instantiateIn($parent); +} +interface IButtonControl +{ +	public function getText(); +	public function setText($value); +	public function getCausesValidation(); +	public function setCausesValidation($value); +	public function getCommandName(); +	public function setCommandName($value); +	public function getCommandParameter(); +	public function setCommandParameter($value); +	public function getValidationGroup(); +	public function setValidationGroup($value); +	public function onClick($param); +	public function onCommand($param); +	public function setIsDefaultButton($value); +	public function getIsDefaultButton(); +} +interface ISurroundable +{ +	public function getSurroundingTagID(); +} +class TBroadcastEventParameter extends TEventParameter +{ +	private $_name; +	private $_param; +	public function __construct($name='',$parameter=null) +	{ +		$this->_name=$name; +		$this->_param=$parameter; +	} +	public function getName() +	{ +		return $this->_name; +	} +	public function setName($value) +	{ +		$this->_name=$value; +	} +	public function getParameter() +	{ +		return $this->_param; +	} +	public function setParameter($value) +	{ +		$this->_param=$value; +	} +} +class TCommandEventParameter extends TEventParameter +{ +	private $_name; +	private $_param; +	public function __construct($name='',$parameter='') +	{ +		$this->_name=$name; +		$this->_param=$parameter; +	} +	public function getCommandName() +	{ +		return $this->_name; +	} +	public function getCommandParameter() +	{ +		return $this->_param; +	} +} +class TCompositeLiteral extends TComponent implements IRenderable, IBindable +{ +	const TYPE_EXPRESSION=0; +	const TYPE_STATEMENTS=1; +	const TYPE_DATABINDING=2; +	private $_container=null; +	private $_items=array(); +	private $_expressions=array(); +	private $_statements=array(); +	private $_bindings=array(); +	public function __construct($items) +	{ +		$this->_items=array(); +		$this->_expressions=array(); +		$this->_statements=array(); +		foreach($items as $id=>$item) +		{ +			if(is_array($item)) +			{ +				if($item[0]===self::TYPE_EXPRESSION) +					$this->_expressions[$id]=$item[1]; +				else if($item[0]===self::TYPE_STATEMENTS) +					$this->_statements[$id]=$item[1]; +				else if($item[0]===self::TYPE_DATABINDING) +					$this->_bindings[$id]=$item[1]; +				$this->_items[$id]=''; +			} +			else +				$this->_items[$id]=$item; +		} +	} +	public function getContainer() +	{ +		return $this->_container; +	} +	public function setContainer(TComponent $value) +	{ +		$this->_container=$value; +	} +	public function evaluateDynamicContent() +	{ +		$context=$this->_container===null?$this:$this->_container; +		foreach($this->_expressions as $id=>$expression) +			$this->_items[$id]=$context->evaluateExpression($expression); +		foreach($this->_statements as $id=>$statement) +			$this->_items[$id]=$context->evaluateStatements($statement); +	} +	public function dataBind() +	{ +		$context=$this->_container===null?$this:$this->_container; +		foreach($this->_bindings as $id=>$binding) +			$this->_items[$id]=$context->evaluateExpression($binding); +	} +	public function render($writer) +	{ +		$writer->write(implode('',$this->_items)); +	} +} +class TFont extends TComponent +{ +	const IS_BOLD=0x01; +	const IS_ITALIC=0x02; +	const IS_OVERLINE=0x04; +	const IS_STRIKEOUT=0x08; +	const IS_UNDERLINE=0x10; +	const IS_SET_BOLD=0x01000; +	const IS_SET_ITALIC=0x02000; +	const IS_SET_OVERLINE=0x04000; +	const IS_SET_STRIKEOUT=0x08000; +	const IS_SET_UNDERLINE=0x10000; +	const IS_SET_SIZE=0x20000; +	const IS_SET_NAME=0x40000; +	private $_flags=0; +	private $_name=''; +	private $_size=''; +	public function getBold() +	{ +		return ($this->_flags & self::IS_BOLD)!==0; +	} +	public function setBold($value) +	{ +		$this->_flags |= self::IS_SET_BOLD; +		if(TPropertyValue::ensureBoolean($value)) +			$this->_flags |= self::IS_BOLD; +		else +			$this->_flags &= ~self::IS_BOLD; +	} +	public function getItalic() +	{ +		return ($this->_flags & self::IS_ITALIC)!==0; +	} +	public function setItalic($value) +	{ +		$this->_flags |= self::IS_SET_ITALIC; +		if(TPropertyValue::ensureBoolean($value)) +			$this->_flags |= self::IS_ITALIC; +		else +			$this->_flags &= ~self::IS_ITALIC; +	} +	public function getOverline() +	{ +		return ($this->_flags & self::IS_OVERLINE)!==0; +	} +	public function setOverline($value) +	{ +		$this->_flags |= self::IS_SET_OVERLINE; +		if(TPropertyValue::ensureBoolean($value)) +			$this->_flags |= self::IS_OVERLINE; +		else +			$this->_flags &= ~self::IS_OVERLINE; +	} +	public function getSize() +	{ +		return $this->_size; +	} +	public function setSize($value) +	{ +		$this->_flags |= self::IS_SET_SIZE; +		$this->_size=$value; +	} +	public function getStrikeout() +	{ +		return ($this->_flags & self::IS_STRIKEOUT)!==0; +	} +	public function setStrikeout($value) +	{ +		$this->_flags |= self::IS_SET_STRIKEOUT; +		if(TPropertyValue::ensureBoolean($value)) +			$this->_flags |= self::IS_STRIKEOUT; +		else +			$this->_flags &= ~self::IS_STRIKEOUT; +	} +	public function getUnderline() +	{ +		return ($this->_flags & self::IS_UNDERLINE)!==0; +	} +	public function setUnderline($value) +	{ +		$this->_flags |= self::IS_SET_UNDERLINE; +		if(TPropertyValue::ensureBoolean($value)) +			$this->_flags |= self::IS_UNDERLINE; +		else +			$this->_flags &= ~self::IS_UNDERLINE; +	} +	public function getName() +	{ +		return $this->_name; +	} +	public function setName($value) +	{ +		$this->_flags |= self::IS_SET_NAME; +		$this->_name=$value; +	} +	public function getIsEmpty() +	{ +		return !$this->_flags; +	} +	public function reset() +	{ +		$this->_flags=0; +		$this->_name=''; +		$this->_size=''; +	} +	public function mergeWith($font) +	{ +		if($font===null || $font->_flags===0) +			return; +		if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD)) +			$this->setBold($font->getBold()); +		if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC)) +			$this->setItalic($font->getItalic()); +		if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE)) +			$this->setOverline($font->getOverline()); +		if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT)) +			$this->setStrikeout($font->getStrikeout()); +		if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE)) +			$this->setUnderline($font->getUnderline()); +		if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE)) +			$this->setSize($font->getSize()); +		if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME)) +			$this->setName($font->getName()); +	} +	public function copyFrom($font) +	{ +		if($font===null || $font->_flags===0) +			return; +		if($font->_flags & self::IS_SET_BOLD) +			$this->setBold($font->getBold()); +		if($font->_flags & self::IS_SET_ITALIC) +			$this->setItalic($font->getItalic()); +		if($font->_flags & self::IS_SET_OVERLINE) +			$this->setOverline($font->getOverline()); +		if($font->_flags & self::IS_SET_STRIKEOUT) +			$this->setStrikeout($font->getStrikeout()); +		if($font->_flags & self::IS_SET_UNDERLINE) +			$this->setUnderline($font->getUnderline()); +		if($font->_flags & self::IS_SET_SIZE) +			$this->setSize($font->getSize()); +		if($font->_flags & self::IS_SET_NAME) +			$this->setName($font->getName()); +	} +	public function toString() +	{ +		if($this->_flags===0) +			return ''; +		$str=''; +		if($this->_flags & self::IS_SET_BOLD) +			$str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;'); +		if($this->_flags & self::IS_SET_ITALIC) +			$str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;'); +		$textDec=''; +		if($this->_flags & self::IS_UNDERLINE) +			$textDec.='underline'; +		if($this->_flags & self::IS_OVERLINE) +			$textDec.=' overline'; +		if($this->_flags & self::IS_STRIKEOUT) +			$textDec.=' line-through'; +		$textDec=ltrim($textDec); +		if($textDec!=='') +			$str.='text-decoration:'.$textDec.';'; +		if($this->_size!=='') +			$str.='font-size:'.$this->_size.';'; +		if($this->_name!=='') +			$str.='font-family:'.$this->_name.';'; +		return $str; +	} +	public function addAttributesToRender($writer) +	{ +		if($this->_flags===0) +			return; +		if($this->_flags & self::IS_SET_BOLD) +			$writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal')); +		if($this->_flags & self::IS_SET_ITALIC) +			$writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal')); +		$textDec=''; +		if($this->_flags & self::IS_UNDERLINE) +			$textDec.='underline'; +		if($this->_flags & self::IS_OVERLINE) +			$textDec.=' overline'; +		if($this->_flags & self::IS_STRIKEOUT) +			$textDec.=' line-through'; +		$textDec=ltrim($textDec); +		if($textDec!=='') +			$writer->addStyleAttribute('text-decoration',$textDec); +		if($this->_size!=='') +			$writer->addStyleAttribute('font-size',$this->_size); +		if($this->_name!=='') +			$writer->addStyleAttribute('font-family',$this->_name); +	} +} +class TStyle extends TComponent +{ +	private $_fields=array(); +	private $_font=null; +	private $_class=null; +	private $_customStyle=null; +	private $_displayStyle='Fixed'; +	public function __construct($style=null) +	{ +		if($style!==null) +			$this->copyFrom($style); +	} +	public function __clone() +	{ +		if($this->_font!==null) +			$this->_font = clone($this->_font); +	} +	public function getBackColor() +	{ +		return isset($this->_fields['background-color'])?$this->_fields['background-color']:''; +	} +	public function setBackColor($value) +	{ +		if(trim($value)==='') +			unset($this->_fields['background-color']); +		else +			$this->_fields['background-color']=$value; +	} +	public function getBorderColor() +	{ +		return isset($this->_fields['border-color'])?$this->_fields['border-color']:''; +	} +	public function setBorderColor($value) +	{ +		if(trim($value)==='') +			unset($this->_fields['border-color']); +		else +			$this->_fields['border-color']=$value; +	} +	public function getBorderStyle() +	{ +		return isset($this->_fields['border-style'])?$this->_fields['border-style']:''; +	} +	public function setBorderStyle($value) +	{ +		if(trim($value)==='') +			unset($this->_fields['border-style']); +		else +			$this->_fields['border-style']=$value; +	} +	public function getBorderWidth() +	{ +		return isset($this->_fields['border-width'])?$this->_fields['border-width']:''; +	} +	public function setBorderWidth($value) +	{ +		if(trim($value)==='') +			unset($this->_fields['border-width']); +		else +			$this->_fields['border-width']=$value; +	} +	public function getCssClass() +	{ +		return $this->_class===null?'':$this->_class; +	} +	public function hasCssClass() +	{ +		return ($this->_class!==null); +	} +	public function setCssClass($value) +	{ +		$this->_class=$value; +	} +	public function getFont() +	{ +		if($this->_font===null) +			$this->_font=new TFont; +		return $this->_font; +	} +	public function hasFont() +	{ +		return $this->_font !== null; +	} +	public function setDisplayStyle($value) +	{ +		$this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle'); +		switch($this->_displayStyle) +		{ +			case TDisplayStyle::None: +				$this->_fields['display'] = 'none'; +				break; +			case TDisplayStyle::Dynamic: +				$this->_fields['display'] = '';  +				break; +			case TDisplayStyle::Fixed: +				$this->_fields['visibility'] = 'visible'; +				break; +			case TDisplayStyle::Hidden: +				$this->_fields['visibility'] = 'hidden'; +				break; +		} +	} +	public function getDisplayStyle() +	{ +		return $this->_displayStyle; +	} +	public function getForeColor() +	{ +		return isset($this->_fields['color'])?$this->_fields['color']:''; +	} +	public function setForeColor($value) +	{ +		if(trim($value)==='') +			unset($this->_fields['color']); +		else +			$this->_fields['color']=$value; +	} +	public function getHeight() +	{ +		return isset($this->_fields['height'])?$this->_fields['height']:''; +	} +	public function setHeight($value) +	{ +		if(trim($value)==='') +			unset($this->_fields['height']); +		else +			$this->_fields['height']=$value; +	} +	public function getCustomStyle() +	{ +		return $this->_customStyle===null?'':$this->_customStyle; +	} +	public function setCustomStyle($value) +	{ +		$this->_customStyle=$value; +	} +	public function getStyleField($name) +	{ +		return isset($this->_fields[$name])?$this->_fields[$name]:''; +	} +	public function setStyleField($name,$value) +	{ +		$this->_fields[$name]=$value; +	} +	public function clearStyleField($name) +	{ +		unset($this->_fields[$name]); +	} +	public function hasStyleField($name) +	{ +		return isset($this->_fields[$name]); +	} +	public function getWidth() +	{ +		return isset($this->_fields['width'])?$this->_fields['width']:''; +	} +	public function setWidth($value) +	{ +		$this->_fields['width']=$value; +	} +	public function reset() +	{ +		$this->_fields=array(); +		$this->_font=null; +		$this->_class=null; +		$this->_customStyle=null; +	} +	public function copyFrom($style) +	{ +		if($style instanceof TStyle) +		{ +			$this->_fields=array_merge($this->_fields,$style->_fields); +			if($style->_class!==null) +				$this->_class=$style->_class; +			if($style->_customStyle!==null) +				$this->_customStyle=$style->_customStyle; +			if($style->_font!==null) +				$this->getFont()->copyFrom($style->_font); +		} +	} +	public function mergeWith($style) +	{ +		if($style instanceof TStyle) +		{ +			$this->_fields=array_merge($style->_fields,$this->_fields); +			if($this->_class===null) +				$this->_class=$style->_class; +			if($this->_customStyle===null) +				$this->_customStyle=$style->_customStyle; +			if($style->_font!==null) +				$this->getFont()->mergeWith($style->_font); +		} +	} +	public function addAttributesToRender($writer) +	{ +		if($this->_customStyle!==null) +		{ +			foreach(explode(';',$this->_customStyle) as $style) +			{ +				$arr=explode(':',$style); +				if(isset($arr[1]) && trim($arr[0])!=='') +					$writer->addStyleAttribute(trim($arr[0]),trim($arr[1])); +			} +		} +		$writer->addStyleAttributes($this->_fields); +		if($this->_font!==null) +			$this->_font->addAttributesToRender($writer); +		if($this->_class!==null) +			$writer->addAttribute('class',$this->_class); +	} +	public function getStyleFields() +	{ +		return $this->_fields; +	} +} +class TDisplayStyle extends TEnumerable +{ +	const None='None'; +	const Dynamic='Dynamic'; +	const Fixed='Fixed'; +	const Hidden='Hidden'; +} +class TTableStyle extends TStyle +{ +	private $_backImageUrl=null; +	private $_horizontalAlign=null; +	private $_cellPadding=null; +	private $_cellSpacing=null; +	private $_gridLines=null; +	private $_borderCollapse=null; +	public function reset() +	{ +		$this->_backImageUrl=null; +		$this->_horizontalAlign=null; +		$this->_cellPadding=null; +		$this->_cellSpacing=null; +		$this->_gridLines=null; +		$this->_borderCollapse=null; +	} +	public function copyFrom($style) +	{ +		parent::copyFrom($style); +		if($style instanceof TTableStyle) +		{ +			if($style->_backImageUrl!==null) +				$this->_backImageUrl=$style->_backImageUrl; +			if($style->_horizontalAlign!==null) +				$this->_horizontalAlign=$style->_horizontalAlign; +			if($style->_cellPadding!==null) +				$this->_cellPadding=$style->_cellPadding; +			if($style->_cellSpacing!==null) +				$this->_cellSpacing=$style->_cellSpacing; +			if($style->_gridLines!==null) +				$this->_gridLines=$style->_gridLines; +			if($style->_borderCollapse!==null) +				$this->_borderCollapse=$style->_borderCollapse; +		} +	} +	public function mergeWith($style) +	{ +		parent::mergeWith($style); +		if($style instanceof TTableStyle) +		{ +			if($this->_backImageUrl===null && $style->_backImageUrl!==null) +				$this->_backImageUrl=$style->_backImageUrl; +			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null) +				$this->_horizontalAlign=$style->_horizontalAlign; +			if($this->_cellPadding===null && $style->_cellPadding!==null) +				$this->_cellPadding=$style->_cellPadding; +			if($this->_cellSpacing===null && $style->_cellSpacing!==null) +				$this->_cellSpacing=$style->_cellSpacing; +			if($this->_gridLines===null && $style->_gridLines!==null) +				$this->_gridLines=$style->_gridLines; +			if($this->_borderCollapse===null && $style->_borderCollapse!==null) +				$this->_borderCollapse=$style->_borderCollapse; +		} +	} +	public function addAttributesToRender($writer) +	{ +		if(($url=trim($this->getBackImageUrl()))!=='') +			$writer->addStyleAttribute('background-image','url('.$url.')'); +		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet) +			$writer->addStyleAttribute('text-align',strtolower($horizontalAlign)); +		if(($cellPadding=$this->getCellPadding())>=0) +			$writer->addAttribute('cellpadding',"$cellPadding"); +		if(($cellSpacing=$this->getCellSpacing())>=0) +			$writer->addAttribute('cellspacing',"$cellSpacing"); +		if($this->getBorderCollapse()) +			$writer->addStyleAttribute('border-collapse','collapse'); +		switch($this->getGridLines()) +		{ +			case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break; +			case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break; +			case TTableGridLines::Both : $writer->addAttribute('rules','all'); break; +		} +		parent::addAttributesToRender($writer); +	} +	public function getBackImageUrl() +	{ +		return $this->_backImageUrl===null?'':$this->_backImageUrl; +	} +	public function setBackImageUrl($value) +	{ +		$this->_backImageUrl=$value; +	} +	public function getHorizontalAlign() +	{ +		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign; +	} +	public function setHorizontalAlign($value) +	{ +		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign'); +	} +	public function getCellPadding() +	{ +		return $this->_cellPadding===null?-1:$this->_cellPadding; +	} +	public function setCellPadding($value) +	{ +		if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1) +			throw new TInvalidDataValueException('tablestyle_cellpadding_invalid'); +	} +	public function getCellSpacing() +	{ +		return $this->_cellSpacing===null?-1:$this->_cellSpacing; +	} +	public function setCellSpacing($value) +	{ +		if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1) +			throw new TInvalidDataValueException('tablestyle_cellspacing_invalid'); +	} +	public function getGridLines() +	{ +		return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines; +	} +	public function setGridLines($value) +	{ +		$this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines'); +	} +	public function getBorderCollapse() +	{ +		return $this->_borderCollapse===null?false:$this->_borderCollapse; +	} +	public function setBorderCollapse($value) +	{ +		$this->_borderCollapse=TPropertyValue::ensureBoolean($value); +	} +} +class TTableItemStyle extends TStyle +{ +	private $_horizontalAlign=null; +	private $_verticalAlign=null; +	private $_wrap=null; +	public function reset() +	{ +		parent::reset(); +		$this->_verticalAlign=null; +		$this->_horizontalAlign=null; +		$this->_wrap=null; +	} +	public function copyFrom($style) +	{ +		parent::copyFrom($style); +		if($style instanceof TTableItemStyle) +		{ +			if($this->_verticalAlign===null && $style->_verticalAlign!==null) +				$this->_verticalAlign=$style->_verticalAlign; +			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null) +				$this->_horizontalAlign=$style->_horizontalAlign; +			if($this->_wrap===null && $style->_wrap!==null) +				$this->_wrap=$style->_wrap; +		} +	} +	public function mergeWith($style) +	{ +		parent::mergeWith($style); +		if($style instanceof TTableItemStyle) +		{ +			if($style->_verticalAlign!==null) +				$this->_verticalAlign=$style->_verticalAlign; +			if($style->_horizontalAlign!==null) +				$this->_horizontalAlign=$style->_horizontalAlign; +			if($style->_wrap!==null) +				$this->_wrap=$style->_wrap; +		} +	} +	public function addAttributesToRender($writer) +	{ +		if(!$this->getWrap()) +			$writer->addStyleAttribute('white-space','nowrap'); +		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet) +			$writer->addAttribute('align',strtolower($horizontalAlign)); +		if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet) +			$writer->addAttribute('valign',strtolower($verticalAlign)); +		parent::addAttributesToRender($writer); +	} +	public function getHorizontalAlign() +	{ +		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign; +	} +	public function setHorizontalAlign($value) +	{ +		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign'); +	} +	public function getVerticalAlign() +	{ +		return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign; +	} +	public function setVerticalAlign($value) +	{ +		$this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign'); +	} +	public function getWrap() +	{ +		return $this->_wrap===null?true:$this->_wrap; +	} +	public function setWrap($value) +	{ +		$this->_wrap=TPropertyValue::ensureBoolean($value); +	} +} +class THorizontalAlign extends TEnumerable +{ +	const NotSet='NotSet'; +	const Left='Left'; +	const Right='Right'; +	const Center='Center'; +	const Justify='Justify'; +} +class TVerticalAlign extends TEnumerable +{ +	const NotSet='NotSet'; +	const Top='Top'; +	const Bottom='Bottom'; +	const Middle='Middle'; +} +class TTableGridLines extends TEnumerable +{ +	const None='None'; +	const Horizontal='Horizontal'; +	const Vertical='Vertical'; +	const Both='Both'; +} +class TWebControlAdapter extends TControlAdapter +{ +	public function render($writer) +	{ +		$this->renderBeginTag($writer); +		$this->renderContents($writer); +		$this->renderEndTag($writer); +	} +	public function renderBeginTag($writer) +	{ +		$this->getControl()->renderBeginTag($writer); +	} +	public function renderContents($writer) +	{ +		$this->getControl()->renderContents($writer); +	} +	public function renderEndTag($writer) +	{ +		$this->getControl()->renderEndTag($writer); +	} +} +class TWebControl extends TControl implements IStyleable +{ +	public function copyBaseAttributes(TWebControl $control) +	{ +		$this->setAccessKey($control->getAccessKey()); +		$this->setToolTip($control->getToolTip()); +		$this->setTabIndex($control->getTabIndex()); +		if(!$control->getEnabled()) +			$this->setEnabled(false); +		if($control->getHasAttributes()) +			$this->getAttributes()->copyFrom($control->getAttributes()); +	} +	public function getAccessKey() +	{ +		return $this->getViewState('AccessKey',''); +	} +	public function setAccessKey($value) +	{ +		if(strlen($value)>1) +			throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value); +		$this->setViewState('AccessKey',$value,''); +	} +	public function getBackColor() +	{ +		if($style=$this->getViewState('Style',null)) +			return $style->getBackColor(); +		else +			return ''; +	} +	public function setBackColor($value) +	{ +		$this->getStyle()->setBackColor($value); +	} +	public function getBorderColor() +	{ +		if($style=$this->getViewState('Style',null)) +			return $style->getBorderColor(); +		else +			return ''; +	} +	public function setBorderColor($value) +	{ +		$this->getStyle()->setBorderColor($value); +	} +	public function getBorderStyle() +	{ +		if($style=$this->getViewState('Style',null)) +			return $style->getBorderStyle(); +		else +			return ''; +	} +	public function setBorderStyle($value) +	{ +		$this->getStyle()->setBorderStyle($value); +	} +	public function getBorderWidth() +	{ +		if($style=$this->getViewState('Style',null)) +			return $style->getBorderWidth(); +		else +			return ''; +	} +	public function setBorderWidth($value) +	{ +		$this->getStyle()->setBorderWidth($value); +	} +	public function getFont() +	{ +		return $this->getStyle()->getFont(); +	} +	public function getForeColor() +	{ +		if($style=$this->getViewState('Style',null)) +			return $style->getForeColor(); +		else +			return ''; +	} +	public function setForeColor($value) +	{ +		$this->getStyle()->setForeColor($value); +	} +	public function getHeight() +	{ +		if($style=$this->getViewState('Style',null)) +			return $style->getHeight(); +		else +			return ''; +	} +	public function setDisplay($value) +	{ +		$this->getStyle()->setDisplayStyle($value); +	} +	public function getDisplay() +	{ +		return $this->getStyle()->getDisplayStyle(); +	} +	public function setCssClass($value) +	{ +		$this->getStyle()->setCssClass($value); +	} +	public function getCssClass() +	{ +		if($style=$this->getViewState('Style',null)) +			return $style->getCssClass(); +		else +			return ''; +	} +	public function setHeight($value) +	{ +		$this->getStyle()->setHeight($value); +	} +	public function getHasStyle() +	{ +		return $this->getViewState('Style',null)!==null; +	} +	protected function createStyle() +	{ +		return new TStyle; +	} +	public function getStyle() +	{ +		if($style=$this->getViewState('Style',null)) +			return $style; +		else +		{ +			$style=$this->createStyle(); +			$this->setViewState('Style',$style,null); +			return $style; +		} +	} +	public function setStyle($value) +	{ +		if(is_string($value)) +			$this->getStyle()->setCustomStyle($value); +		else +			throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this)); +	} +	public function clearStyle() +	{ +		$this->clearViewState('Style'); +	} +	public function getTabIndex() +	{ +		return $this->getViewState('TabIndex',0); +	} +	public function setTabIndex($value) +	{ +		$this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0); +	} +	protected function getTagName() +	{ +		return 'span'; +	} +	public function getToolTip() +	{ +		return $this->getViewState('ToolTip',''); +	} +	public function setToolTip($value) +	{ +		$this->setViewState('ToolTip',$value,''); +	} +	public function getWidth() +	{ +		if($style=$this->getViewState('Style',null)) +			return $style->getWidth(); +		else +			return ''; +	} +	public function setWidth($value) +	{ +		$this->getStyle()->setWidth($value); +	} +	protected function addAttributesToRender($writer) +	{ +		if($this->getID()!=='') +			$writer->addAttribute('id',$this->getClientID()); +		if(($accessKey=$this->getAccessKey())!=='') +			$writer->addAttribute('accesskey',$accessKey); +		if(!$this->getEnabled()) +			$writer->addAttribute('disabled','disabled'); +		if(($tabIndex=$this->getTabIndex())>0) +			$writer->addAttribute('tabindex',"$tabIndex"); +		if(($toolTip=$this->getToolTip())!=='') +			$writer->addAttribute('title',$toolTip); +		if($style=$this->getViewState('Style',null)) +			$style->addAttributesToRender($writer); +		if($this->getHasAttributes()) +		{ +			foreach($this->getAttributes() as $name=>$value) +				$writer->addAttribute($name,$value); +		} +	} +	public function render($writer) +	{ +		$this->renderBeginTag($writer); +		$this->renderContents($writer); +		$this->renderEndTag($writer); +	} +	public function renderBeginTag($writer) +	{ +		$this->addAttributesToRender($writer); +		$writer->renderBeginTag($this->getTagName()); +	} +	public function renderContents($writer) +	{ +		parent::renderChildren($writer); +	} +	public function renderEndTag($writer) +	{ +		$writer->renderEndTag(); +	} +} +class TCompositeControl extends TControl implements INamingContainer +{ +	protected function initRecursive($namingContainer=null) +	{ +		$this->ensureChildControls(); +		parent::initRecursive($namingContainer); +	} +} +class TTemplateControl extends TCompositeControl +{ +	const EXT_TEMPLATE='.tpl'; +	private static $_template=array(); +	private $_localTemplate=null; +	private $_master=null; +	private $_masterClass=''; +	private $_contents=array(); +	private $_placeholders=array(); +	public function getTemplate() +	{ +		if($this->_localTemplate===null) +		{ +			$class=get_class($this); +			if(!isset(self::$_template[$class])) +				self::$_template[$class]=$this->loadTemplate(); +			return self::$_template[$class]; +		} +		else +			return $this->_localTemplate; +	} +	public function setTemplate($value) +	{ +		$this->_localTemplate=$value; +	} +	public function getIsSourceTemplateControl() +	{ +		if(($template=$this->getTemplate())!==null) +			return $template->getIsSourceTemplate(); +		else +			return false; +	} +	public function getTemplateDirectory() +	{ +		if(($template=$this->getTemplate())!==null) +			return $template->getContextPath(); +		else +			return ''; +	} +	protected function loadTemplate() +	{ +		$template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this)); +		return $template; +	} +	public function createChildControls() +	{ +		if($tpl=$this->getTemplate()) +		{ +			foreach($tpl->getDirective() as $name=>$value) +			{ +				if(is_string($value)) +					$this->setSubProperty($name,$value); +				else +					throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name); +			} +			$tpl->instantiateIn($this); +		} +	} +	public function registerContent($id,TContent $object) +	{ +		if(isset($this->_contents[$id])) +			throw new TConfigurationException('templatecontrol_contentid_duplicated',$id); +		else +			$this->_contents[$id]=$object; +	} +	public function registerContentPlaceHolder($id,TContentPlaceHolder $object) +	{ +		if(isset($this->_placeholders[$id])) +			throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id); +		else +			$this->_placeholders[$id]=$object; +	} +	public function getMasterClass() +	{ +		return $this->_masterClass; +	} +	public function setMasterClass($value) +	{ +		$this->_masterClass=$value; +	} +	public function getMaster() +	{ +		return $this->_master; +	} +	public function injectContent($id,$content) +	{ +		if(isset($this->_placeholders[$id])) +		{ +			$placeholder=$this->_placeholders[$id]; +			$controls=$placeholder->getParent()->getControls(); +			$loc=$controls->remove($placeholder); +			$controls->insertAt($loc,$content); +		} +		else +			throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id); +	} +	protected function initRecursive($namingContainer=null) +	{ +		$this->ensureChildControls(); +		if($this->_masterClass!=='') +		{ +			$master=Prado::createComponent($this->_masterClass); +			if(!($master instanceof TTemplateControl)) +				throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid'); +			$this->_master=$master; +			$this->getControls()->clear(); +			$this->getControls()->add($master); +			$master->ensureChildControls(); +			foreach($this->_contents as $id=>$content) +				$master->injectContent($id,$content); +		} +		else if(!empty($this->_contents)) +			throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this)); +		parent::initRecursive($namingContainer); +	} +} +class TForm extends TControl +{ +	public function onInit($param) +	{ +		parent::onInit($param); +		$this->getPage()->setForm($this); +	} +	protected function addAttributesToRender($writer) +	{ +		$writer->addAttribute('id',$this->getClientID()); +		$writer->addAttribute('method',$this->getMethod()); +		$uri=$this->getRequest()->getRequestURI(); +		$writer->addAttribute('action',str_replace('&','&',str_replace('&','&',$uri))); +		if(($enctype=$this->getEnctype())!=='') +			$writer->addAttribute('enctype',$enctype); +		$attributes=$this->getAttributes(); +		$attributes->remove('action'); +		$writer->addAttributes($attributes); +		if(($butt=$this->getDefaultButton())!=='') +		{ +			if(($button=$this->findControl($butt))!==null) +				$this->getPage()->getClientScript()->registerDefaultButton($this, $button); +			else +				throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt); +		} +	} +	public function render($writer) +	{ +		$page=$this->getPage(); +		$page->beginFormRender($writer); +		$textWriter=new TTextWriter; +		$this->renderChildren(new THtmlWriter($textWriter)); +		$content=$textWriter->flush(); +		$page->endFormRender($writer); +		$this->addAttributesToRender($writer); +		$writer->renderBeginTag('form'); +		$cs=$page->getClientScript(); +		if($page->getClientSupportsJavaScript()) +		{ +			$cs->renderHiddenFields($writer); +			$cs->renderScriptFiles($writer); +			$cs->renderBeginScripts($writer); +			$writer->write($content); +			$cs->renderEndScripts($writer); +		} +		else +		{ +			$cs->renderHiddenFields($writer); +			$writer->write($content); +		} +		$writer->renderEndTag(); +	} +	public function getDefaultButton() +	{ +		return $this->getViewState('DefaultButton',''); +	} +	public function setDefaultButton($value) +	{ +		$this->setViewState('DefaultButton',$value,''); +	} +	public function getMethod() +	{ +		return $this->getViewState('Method','post'); +	} +	public function setMethod($value) +	{ +		$this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post'); +	} +	public function getEnctype() +	{ +		return $this->getViewState('Enctype',''); +	} +	public function setEnctype($value) +	{ +		$this->setViewState('Enctype',$value,''); +	} +	public function getName() +	{ +		return $this->getUniqueID(); +	} +} +class TClientScriptManager extends TApplicationComponent +{ +	const SCRIPT_PATH='Web/Javascripts/source'; +	const SCRIPT_LOADER='Web/Javascripts/clientscripts.php'; +	private $_page; +	private $_hiddenFields=array(); +	private $_beginScripts=array(); +	private $_endScripts=array(); +	private $_scriptFiles=array(); +	private $_headScriptFiles=array(); +	private $_headScripts=array(); +	private $_styleSheetFiles=array(); +	private $_styleSheets=array(); +	private $_registeredPradoScripts=array(); +	private static $_pradoScripts; +	 private static $_pradoPackages; +	public function __construct(TPage $owner) +	{ +		$this->_page=$owner; +	} +	public function getRequiresHead() +	{ +		return count($this->_styleSheetFiles) || count($this->_styleSheets) +			|| count($this->_headScriptFiles) || count($this->_headScripts); +	} +	public function registerPradoScript($name) +	{ +		$this->registerPradoScriptInternal($name); +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params); +	} +	private function registerPradoScriptInternal($name) +	{ +		if(!isset($this->_registeredPradoScripts[$name])) +		{ +			if(self::$_pradoScripts === null) +			{ +				$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH.'/packages.php'; +				list($packages,$deps)= include($packageFile); +				self::$_pradoScripts = $deps; +				self::$_pradoPackages = $packages; +			} +			if(isset(self::$_pradoScripts[$name])) +				$this->_registeredPradoScripts[$name]=true; +			else +				throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name); +		} +	} +	public function getPradoScriptAssetUrl() +	{ +		$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; +		$assets = Prado::getApplication()->getAssetManager(); +		return $assets->getPublishedUrl($base); +	} +	protected function renderPradoScripts($writer) +	{ +		if(($packages=array_keys($this->_registeredPradoScripts))!==array()) +		{ +			if (Prado::getApplication()->getMode()!==TApplicationMode::Debug) +			{ +				$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; +				$url = $this->registerJavascriptPackages($base, $packages); +				$writer->write(TJavaScript::renderScriptFile($url)); +			} +			else +			{ +								$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; +				list($path,$baseUrl)=$this->getPackagePathUrl($base); +				$packagesUrl=array(); +				foreach ($packages as $p) +				{ +					foreach (self::$_pradoScripts[$p] as $dep) +					{ +						foreach (self::$_pradoPackages[$dep] as $script) +						{ +							if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl)) +								$packagesUrl[]=$url; +						} +					} +				} +				$writer->write(TJavaScript::renderScriptFiles($packagesUrl)); +			} +		} +	} +	public function registerJavascriptPackages($base, $packages, $debug=null, $gzip=true) +	{ +		list($path,$url) = $this->getPackagePathUrl($base); +		$scriptLoaderPath = $path.'/'.basename(self::SCRIPT_LOADER); +		$scriptLoaderSrc = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_LOADER; +		if(!is_file($scriptLoaderPath)) +		{ +			copy($scriptLoaderSrc, $scriptLoaderPath); +			chmod($scriptLoaderPath, PRADO_CHMOD); +		} +		$url .= '/'.basename(self::SCRIPT_LOADER).'?js='.implode(',', $packages); +		if($debug!==false && $this->getApplication()->getMode()===TApplicationMode::Debug) +		{ +			$this->verifyJavascriptPackages($base,$path,$packages); +			$url.='&mode=debug'; +		} +		if($gzip===false) +			$url.='&gzip=false'; +		return $url; +	} +	protected function verifyJavascriptPackages($base,$path,$scripts) +	{ +		$file = $path.'/packages.php'; +		if(is_file($file)) +		{ +			list($packs,$deps) = include($file); +			if(count($missing = array_diff($scripts, array_keys($deps))) > 0) +			{ +				throw new TConfigurationException('csmanager_invalid_packages', +					$base.'/packages.php',implode(', ', $missing), implode(', ', array_keys($deps))); +			} +		} +	} +	protected function getPackagePathUrl($base) +	{ +		$assets = Prado::getApplication()->getAssetManager(); +		if(strpos($base, $assets->getBaseUrl())===false) +		{ +			if(($dir = Prado::getPathOfNameSpace($base)) !== null) { +				$base = $dir; +			} +			return array($assets->getPublishedPath($base), $assets->publishFilePath($base)); +		} +		else +		{ +			return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base); +		} +	} +	public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null) +	{ +		$options = !is_array($options) ? array() : $options; +		$class = new TReflectionClass($callbackHandler); +		$clientSide = $callbackHandler->getActiveControl()->getClientSide(); +		$options = array_merge($options, $clientSide->getOptions()->toArray()); +		$optionString = TJavaScript::encode($options); +		$this->registerPradoScriptInternal('ajax'); +		$id = $callbackHandler->getUniqueID(); +		return "new Prado.CallbackRequest('{$id}',{$optionString})"; +	} +	public function registerCallbackControl($class, $options) +	{ +		$optionString=TJavaScript::encode($options); +		$code="new {$class}({$optionString});"; +		$this->_endScripts[sprintf('%08X', crc32($code))]=$code; +		$this->registerPradoScriptInternal('ajax'); +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params); +	} +	public function registerPostBackControl($class,$options) +	{ +		if($class === null) { +			return; +		} +		if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null) +			$options['FormID']=$form->getClientID(); +		$optionString=TJavaScript::encode($options); +		$code="new {$class}({$optionString});"; +		$this->_endScripts[sprintf('%08X', crc32($code))]=$code; +		$this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]=''; +		$this->_hiddenFields[TPage::FIELD_POSTBACK_PARAMETER]=''; +		$this->registerPradoScriptInternal('prado'); +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params); +	} +	public function registerDefaultButton($panel, $button) +	{ +		$panelID=is_string($panel)?$panel:$panel->getUniqueID(); +		if(is_string($button)) +			$buttonID=$button; +		else +		{ +			$button->setIsDefaultButton(true); +			$buttonID=$button->getUniqueID(); +		} +		$options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID)); +		$code = "new Prado.WebUI.DefaultButton($options);"; +		$this->_endScripts['prado:'.$panelID]=$code; +		$this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]=''; +		$this->registerPradoScriptInternal('prado'); +		$params=array($panelID,$buttonID); +		$this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params); +	} +	protected function getDefaultButtonOptions($panelID, $buttonID) +	{ +		$options['Panel'] = TControl::convertUniqueIdToClientId($panelID); +		$options['Target'] = TControl::convertUniqueIdToClientId($buttonID); +		$options['EventTarget'] = $buttonID; +		$options['Event'] = 'click'; +		return $options; +	} +	public function registerFocusControl($target) +	{ +		$this->registerPradoScriptInternal('effects'); +		if($target instanceof TControl) +			$target=$target->getClientID(); +		$id = TJavaScript::quoteString($target); +		$this->_endScripts['prado:focus'] = 'new Effect.ScrollTo("'.$id.'"); Prado.Element.focus("'.$id.'");'; +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params); +	} +	public function registerStyleSheetFile($key,$url,$media='') +	{ +		if($media==='') +			$this->_styleSheetFiles[$key]=$url; +		else +			$this->_styleSheetFiles[$key]=array($url,$media); +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params); +	} +	public function registerStyleSheet($key,$css,$media='') +	{ +		$this->_styleSheets[$key]=$css; +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params); +	} +	public function registerHeadScriptFile($key,$url) +	{ +		$this->_headScriptFiles[$key]=$url; +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params); +	} +	public function registerHeadScript($key,$script) +	{ +		$this->_headScripts[$key]=$script; +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params); +	} +	public function registerScriptFile($key,$url) +	{ +		$this->_scriptFiles[$key]=$url; +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params); +	} +	public function registerBeginScript($key,$script) +	{ +		$this->_beginScripts[$key]=$script; +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params); +	} +	public function registerEndScript($key,$script) +	{ +		$this->_endScripts[$key]=$script; +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params); +	} +	public function registerHiddenField($name,$value) +	{ +		$this->_hiddenFields[$name]=$value; +		$params=func_get_args(); +		$this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params); +	} +	public function isStyleSheetFileRegistered($key) +	{ +		return isset($this->_styleSheetFiles[$key]); +	} +	public function isStyleSheetRegistered($key) +	{ +		return isset($this->_styleSheets[$key]); +	} +	public function isHeadScriptFileRegistered($key) +	{ +		return isset($this->_headScriptFiles[$key]); +	} +	public function isHeadScriptRegistered($key) +	{ +		return isset($this->_headScripts[$key]); +	} +	public function isScriptFileRegistered($key) +	{ +		return isset($this->_scriptFiles[$key]); +	} +	public function isBeginScriptRegistered($key) +	{ +		return isset($this->_beginScripts[$key]); +	} +	public function isEndScriptRegistered($key) +	{ +		return isset($this->_endScripts[$key]); +	} +	public function hasEndScripts() +	{ +		return count($this->_endScripts) > 0; +	} +	public function hasBeginScripts() +	{ +		return count($this->_beginScripts) > 0; +	} +	public function isHiddenFieldRegistered($key) +	{ +		return isset($this->_hiddenFields[$key]); +	} +	public function renderStyleSheetFiles($writer) +	{ +		$str=''; +		foreach($this->_styleSheetFiles as $url) +		{ +			if(is_array($url)) +				$str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n"; +			else +				$str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n"; +		} +		$writer->write($str); +	} +	public function renderStyleSheets($writer) +	{ +		if(count($this->_styleSheets)) +			$writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n"); +	} +	public function renderHeadScriptFiles($writer) +	{ +		$writer->write(TJavaScript::renderScriptFiles($this->_headScriptFiles)); +	} +	public function renderHeadScripts($writer) +	{ +		$writer->write(TJavaScript::renderScriptBlocks($this->_headScripts)); +	} +	public function renderScriptFiles($writer) +	{ +		$this->renderPradoScripts($writer); +		if(!empty($this->_scriptFiles)) +			$writer->write(TJavaScript::renderScriptFiles($this->_scriptFiles)); +	} +	public function renderBeginScripts($writer) +	{ +		$writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts)); +	} +	public function renderEndScripts($writer) +	{ +		$writer->write(TJavaScript::renderScriptBlocks($this->_endScripts)); +	} +	public function renderHiddenFields($writer) +	{ +		$str=''; +		foreach($this->_hiddenFields as $name=>$value) +		{ +			$id=strtr($name,':','_'); +			if(is_array($value)) +			{ +				foreach($value as $v) +					$str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n"; +			} +			else +			{ +				$str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n"; +			} +		} +		if($str!=='') +			$writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n"); +	} +} +abstract class TClientSideOptions extends TComponent +{ +	private $_options; +	public function __construct() +	{ +		$this->_options = Prado::createComponent('System.Collections.TMap'); +	} +	protected function setFunction($name, $code) +	{ +		if(!TJavaScript::isFunction($code)) +			$code = TJavaScript::quoteFunction($this->ensureFunction($code)); +		$this->setOption($name, $code); +	} +	protected function getOption($name) +	{ +		return $this->_options->itemAt($name); +	} +	protected function setOption($name, $value) +	{ +		$this->_options->add($name, $value); +	} +	public function getOptions() +	{ +		return $this->_options; +	} +	protected function ensureFunction($javascript) +	{ +		return "function(sender, parameter){ {$javascript} }"; +	} +} +class TPage extends TTemplateControl +{ +	const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET'; +	const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER'; +	const FIELD_LASTFOCUS='PRADO_LASTFOCUS'; +	const FIELD_PAGESTATE='PRADO_PAGESTATE'; +	const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET'; +	const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER'; +	private static $_systemPostFields=array( +		'PRADO_POSTBACK_TARGET'=>true, +		'PRADO_POSTBACK_PARAMETER'=>true, +		'PRADO_LASTFOCUS'=>true, +		'PRADO_PAGESTATE'=>true, +		'PRADO_CALLBACK_TARGET'=>true, +		'PRADO_CALLBACK_PARAMETER'=>true +	); +	private $_form; +	private $_head; +	private $_validators=array(); +	private $_validated=false; +	private $_theme; +	private $_title; +	private $_styleSheet; +	private $_clientScript; +	private $_postData; +	private $_restPostData; +	private $_controlsPostDataChanged=array(); +	private $_controlsRequiringPostData=array(); +	private $_controlsRegisteredForPostData=array(); +	private $_postBackEventTarget; +	private $_postBackEventParameter; +	private $_formRendered=false; +	private $_inFormRender=false; +	private $_focus; +	private $_pagePath=''; +	private $_enableStateValidation=true; +	private $_enableStateEncryption=false; +	private $_statePersisterClass='System.Web.UI.TPageStatePersister'; +	private $_statePersister; +	private $_cachingStack; +	private $_clientState=''; +	private $_postDataLoaders=array(); +	private $_isLoadingPostData=false; +	private $_enableJavaScript=true; +	public function __construct() +	{ +		parent::__construct(); +		$this->setPage($this); +	} +	public function run($writer) +	{ +		$this->determinePostBackMode(); +		if($this->getIsPostBack()) +		{ +			if($this->getIsCallback()) +				$this->processCallbackRequest($writer); +			else +				$this->processPostBackRequest($writer); +		} +		else +			$this->processNormalRequest($writer); +	} +	protected function processNormalRequest($writer) +	{ +		$this->onPreInit(null); +		$this->initRecursive(); +		$this->onInitComplete(null); +		$this->onPreLoad(null); +		$this->loadRecursive(); +		$this->onLoadComplete(null); +		$this->preRenderRecursive(); +		$this->onPreRenderComplete(null); +		$this->savePageState(); +		$this->onSaveStateComplete(null); +		$this->renderControl($writer); +		$this->unloadRecursive(); +	} +	protected function processPostBackRequest($writer) +	{ +		$this->onPreInit(null); +		$this->initRecursive(); +		$this->onInitComplete(null); +		$this->_restPostData=new TMap; +		$this->loadPageState(); +		$this->processPostData($this->_postData,true); +		$this->onPreLoad(null); +		$this->loadRecursive(); +		$this->processPostData($this->_restPostData,false); +		$this->raiseChangedEvents(); +		$this->raisePostBackEvent(); +		$this->onLoadComplete(null); +		$this->preRenderRecursive(); +		$this->onPreRenderComplete(null); +		$this->savePageState(); +		$this->onSaveStateComplete(null); +		$this->renderControl($writer); +		$this->unloadRecursive(); +	} +	protected function processCallbackRequest($writer) +	{ +		Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter'); +		$this->setAdapter(new TActivePageAdapter($this)); +        if (($g=$this->getApplication()->getGlobalization(false))!==null &&  +            strtoupper($enc=$g->getCharset())!='UTF-8') +                foreach ($this->_postData as $k=>$v) +                    $this->_postData[$k]=iconv('UTF-8',$enc.'//IGNORE',$v); +		$this->onPreInit(null); +		$this->initRecursive(); +		$this->onInitComplete(null); +		$this->_restPostData=new TMap; +		$this->loadPageState(); +		$this->processPostData($this->_postData,true); +		$this->onPreLoad(null); +		$this->loadRecursive(); +		$this->processPostData($this->_restPostData,false); +		$this->raiseChangedEvents(); +		$this->getAdapter()->processCallbackEvent($writer); +		$this->onLoadComplete(null); +		$this->preRenderRecursive(); +		$this->onPreRenderComplete(null); +		$this->savePageState(); +		$this->onSaveStateComplete(null); +		$this->getAdapter()->renderCallbackResponse($writer); +		$this->unloadRecursive(); +	} +	public function getCallbackClient() +	{ +		if($this->getAdapter() !== null) +			return $this->getAdapter()->getCallbackClientHandler(); +		else +			return new TCallbackClientScript(); +	} +	public function setCallbackClient($client) +	{ +		$this->getAdapter()->setCallbackClientHandler($client); +	} +	public function getCallbackEventTarget() +	{ +		return $this->getAdapter()->getCallbackEventTarget(); +	} +	public function setCallbackEventTarget(TControl $control) +	{ +		$this->getAdapter()->setCallbackEventTarget($control); +	} +	public function getCallbackEventParameter() +	{ +		return $this->getAdapter()->getCallbackEventParameter(); +	} +	public function setCallbackEventParameter($value) +	{ +		$this->getAdapter()->setCallbackEventParameter($value); +	} +	public function registerPostDataLoader($control) +	{ +		$id=is_string($control)?$control:$control->getUniqueID(); +		$this->_postDataLoaders[$id] = true; +	} +	public function getPostDataLoaders() +	{ +		return array_keys($this->_postDataLoaders); +	} +	public function getForm() +	{ +		return $this->_form; +	} +	public function setForm(TForm $form) +	{ +		if($this->_form===null) +			$this->_form=$form; +		else +			throw new TInvalidOperationException('page_form_duplicated'); +	} +	public function getValidators($validationGroup=null) +	{ +		if(!$this->_validators) +			$this->_validators=new TList; +		if($validationGroup===null) +			return $this->_validators; +		else +		{ +			$list=new TList; +			foreach($this->_validators as $validator) +				if($validator->getValidationGroup()===$validationGroup) +					$list->add($validator); +			return $list; +		} +	} +	public function validate($validationGroup=null) +	{ +		$this->_validated=true; +		if($this->_validators && $this->_validators->getCount()) +		{ +			if($validationGroup===null) +			{ +				foreach($this->_validators as $validator) +					$validator->validate(); +			} +			else +			{ +				foreach($this->_validators as $validator) +				{ +					if($validator->getValidationGroup()===$validationGroup) +						$validator->validate(); +				} +			} +		} +	} +	public function getIsValid() +	{ +		if($this->_validated) +		{ +			if($this->_validators && $this->_validators->getCount()) +			{ +				foreach($this->_validators as $validator) +					if(!$validator->getIsValid()) +						return false; +			} +			return true; +		} +		else +			throw new TInvalidOperationException('page_isvalid_unknown'); +	} +	public function getTheme() +	{ +		if(is_string($this->_theme)) +			$this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme); +		return $this->_theme; +	} +	public function setTheme($value) +	{ +		$this->_theme=empty($value)?null:$value; +	} +	public function getStyleSheetTheme() +	{ +		if(is_string($this->_styleSheet)) +			$this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet); +		return $this->_styleSheet; +	} +	public function setStyleSheetTheme($value) +	{ +		$this->_styleSheet=empty($value)?null:$value; +	} +	public function applyControlSkin($control) +	{ +		if(($theme=$this->getTheme())!==null) +			$theme->applySkin($control); +	} +	public function applyControlStyleSheet($control) +	{ +		if(($theme=$this->getStyleSheetTheme())!==null) +			$theme->applySkin($control); +	} +	public function getClientScript() +	{ +		if(!$this->_clientScript) +			$this->_clientScript=new TClientScriptManager($this); +		return $this->_clientScript; +	} +	public function onPreInit($param) +	{ +		$this->raiseEvent('OnPreInit',$this,$param); +	} +	public function onInitComplete($param) +	{ +		$this->raiseEvent('OnInitComplete',$this,$param); +	} +	public function onPreLoad($param) +	{ +		$this->raiseEvent('OnPreLoad',$this,$param); +	} +	public function onLoadComplete($param) +	{ +		$this->raiseEvent('OnLoadComplete',$this,$param); +	} +	public function onPreRenderComplete($param) +	{ +		$this->raiseEvent('OnPreRenderComplete',$this,$param); +		$cs=$this->getClientScript(); +		$theme=$this->getTheme(); +		if($theme instanceof ITheme) +		{ +			foreach($theme->getStyleSheetFiles() as $url) +				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url)); +			foreach($theme->getJavaScriptFiles() as $url) +				$cs->registerHeadScriptFile($url,$url); +		} +		$styleSheet=$this->getStyleSheetTheme(); +		if($styleSheet instanceof ITheme) +		{ +			foreach($styleSheet->getStyleSheetFiles() as $url) +				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url)); +			foreach($styleSheet->getJavaScriptFiles() as $url) +				$cs->registerHeadScriptFile($url,$url); +		} +		if($cs->getRequiresHead() && $this->getHead()===null) +			throw new TConfigurationException('page_head_required'); +	} +	private function getCssMediaType($url) +	{ +		$segs=explode('.',basename($url)); +		if(isset($segs[2])) +			return $segs[count($segs)-2]; +		else +			return ''; +	} +	public function onSaveStateComplete($param) +	{ +		$this->raiseEvent('OnSaveStateComplete',$this,$param); +	} +	private function determinePostBackMode() +	{ +		$postData=$this->getRequest(); +		if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET)) +			$this->_postData=$postData; +	} +	public function getIsPostBack() +	{ +		return $this->_postData!==null; +	} +	public function getIsCallback() +	{ +		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET); +	} +	public function saveState() +	{ +		parent::saveState(); +		$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array()); +	} +	public function loadState() +	{ +		parent::loadState(); +		$this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array()); +	} +	protected function loadPageState() +	{ +		$state=$this->getStatePersister()->load(); +		$this->loadStateRecursive($state,$this->getEnableViewState()); +	} +	protected function savePageState() +	{ +		$state=&$this->saveStateRecursive($this->getEnableViewState()); +		$this->getStatePersister()->save($state); +	} +	protected function isSystemPostField($field) +	{ +		return isset(self::$_systemPostFields[$field]); +	} +	public function registerRequiresPostData($control) +	{ +		$id=is_string($control)?$control:$control->getUniqueID(); +		$this->_controlsRegisteredForPostData[$id]=true; +		$this->registerPostDataLoader($id); +		$params=func_get_args(); +		foreach($this->getCachingStack() as $item) +			$item->registerAction('Page','registerRequiresPostData',$id); +	} +	public function getPostBackEventTarget() +	{ +		if($this->_postBackEventTarget===null && $this->_postData!==null) +		{ +			$eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET); +			if(!empty($eventTarget)) +				$this->_postBackEventTarget=$this->findControl($eventTarget); +		} +		return $this->_postBackEventTarget; +	} +	public function setPostBackEventTarget(TControl $control) +	{ +		$this->_postBackEventTarget=$control; +	} +	public function getPostBackEventParameter() +	{ +		if($this->_postBackEventParameter===null && $this->_postData!==null) +		{ +			if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null) +				$this->_postBackEventParameter=''; +		} +		return $this->_postBackEventParameter; +	} +	public function setPostBackEventParameter($value) +	{ +		$this->_postBackEventParameter=$value; +	} +	protected function processPostData($postData,$beforeLoad) +	{ +		$this->_isLoadingPostData=true; +		if($beforeLoad) +			$this->_restPostData=new TMap; +		foreach($postData as $key=>$value) +		{ +			if($this->isSystemPostField($key)) +				continue; +			else if($control=$this->findControl($key)) +			{ +				if($control instanceof IPostBackDataHandler) +				{ +					if($control->loadPostData($key,$postData)) +						$this->_controlsPostDataChanged[]=$control; +				} +				else if($control instanceof IPostBackEventHandler && +					empty($this->_postData[self::FIELD_POSTBACK_TARGET])) +				{ +					$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);   +				} +				unset($this->_controlsRequiringPostData[$key]); +			} +			else if($beforeLoad) +				$this->_restPostData->add($key,$value); +		} +		foreach($this->_controlsRequiringPostData as $key=>$value) +		{ +			if($control=$this->findControl($key)) +			{ +				if($control instanceof IPostBackDataHandler) +				{ +					if($control->loadPostData($key,$this->_postData)) +						$this->_controlsPostDataChanged[]=$control; +				} +				else +					throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key); +				unset($this->_controlsRequiringPostData[$key]); +			} +		} +		$this->_isLoadingPostData=false; +	} +	public function getIsLoadingPostData() +	{ +		return $this->_isLoadingPostData; +	} +	private function raiseChangedEvents() +	{ +		foreach($this->_controlsPostDataChanged as $control) +			$control->raisePostDataChangedEvent(); +	} +	private function raisePostBackEvent() +	{ +		if(($postBackHandler=$this->getPostBackEventTarget())===null) +			$this->validate(); +		else if($postBackHandler instanceof IPostBackEventHandler) +			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter()); +	} +	public function ensureRenderInForm($control) +	{ +		if(!$this->getIsCallback() && !$this->_inFormRender) +			throw new TConfigurationException('page_control_outofform',get_class($control),$control->getUniqueID()); +	} +	public function beginFormRender($writer) +	{ +		if($this->_formRendered) +			throw new TConfigurationException('page_form_duplicated'); +		$this->_formRendered=true; +		$this->_inFormRender=true; +		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState()); +	} +	public function endFormRender($writer) +	{ +		if($this->_focus) +		{ +			if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true)) +				$focus=$this->_focus->getClientID(); +			else +				$focus=$this->_focus; +			$this->getClientScript()->registerFocusControl($focus); +		} +		else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null) +			$this->getClientScript()->registerFocusControl($lastFocus); +		$this->_inFormRender=false; +	} +	public function setFocus($value) +	{ +		$this->_focus=$value; +	} +	public function getClientSupportsJavaScript() +	{ +		return $this->_enableJavaScript; +	} +	public function setClientSupportsJavaScript($value) +	{ +		$this->_enableJavaScript=TPropertyValue::ensureBoolean($value); +	} +	public function getHead() +	{ +		return $this->_head; +	} +	public function setHead(THead $value) +	{ +		if($this->_head) +			throw new TInvalidOperationException('page_head_duplicated'); +		$this->_head=$value; +		if($this->_title!==null) +		{ +			$this->_head->setTitle($this->_title); +			$this->_title=null; +		} +	} +	public function getTitle() +	{ +		if($this->_head) +			return $this->_head->getTitle(); +		else +			return $this->_title===null ? '' : $this->_title; +	} +	public function setTitle($value) +	{ +		if($this->_head) +			$this->_head->setTitle($value); +		else +			$this->_title=$value; +	} +	public function getClientState() +	{ +		return $this->_clientState; +	} +	public function setClientState($state) +	{ +		$this->_clientState=$state; +	} +	public function getRequestClientState() +	{ +		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE); +	} +	public function getStatePersisterClass() +	{ +		return $this->_statePersisterClass; +	} +	public function setStatePersisterClass($value) +	{ +		$this->_statePersisterClass=$value; +	} +	public function getStatePersister() +	{ +		if($this->_statePersister===null) +		{ +			$this->_statePersister=Prado::createComponent($this->_statePersisterClass); +			if(!($this->_statePersister instanceof IPageStatePersister)) +				throw new TInvalidDataTypeException('page_statepersister_invalid'); +			$this->_statePersister->setPage($this); +		} +		return $this->_statePersister; +	} +	public function getEnableStateValidation() +	{ +		return $this->_enableStateValidation; +	} +	public function setEnableStateValidation($value) +	{ +		$this->_enableStateValidation=TPropertyValue::ensureBoolean($value); +	} +	public function getEnableStateEncryption() +	{ +		return $this->_enableStateEncryption; +	} +	public function setEnableStateEncryption($value) +	{ +		$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value); +	} +	public function getPagePath() +	{ +		return $this->_pagePath; +	} +	public function setPagePath($value) +	{ +		$this->_pagePath=$value; +	} +	public function registerCachingAction($context,$funcName,$funcParams) +	{ +		if($this->_cachingStack) +		{ +			foreach($this->_cachingStack as $cache) +				$cache->registerAction($context,$funcName,$funcParams); +		} +	} +	public function getCachingStack() +	{ +		if(!$this->_cachingStack) +			$this->_cachingStack=new TStack; +		return $this->_cachingStack; +	} +} +interface IPageStatePersister +{ +	public function getPage(); +	public function setPage(TPage $page); +	public function save($state); +	public function load(); +} +class TPageStateFormatter +{ +	public static function serialize($page,$data) +	{ +		$sm=$page->getApplication()->getSecurityManager(); +		if($page->getEnableStateValidation()) +			$str=$sm->hashData(Prado::serialize($data)); +		else +			$str=Prado::serialize($data); +		if(extension_loaded('zlib')) +			$str=gzcompress($str); +		if($page->getEnableStateEncryption()) +			$str=$sm->encrypt($str); +		return base64_encode($str); +	} +	public static function unserialize($page,$data) +	{ +		$str=base64_decode($data); +		if($str==='') +			return null; +		if($str!==false) +		{ +			$sm=$page->getApplication()->getSecurityManager(); +			if($page->getEnableStateEncryption()) +				$str=$sm->decrypt($str); +			if(extension_loaded('zlib')) +				$str=@gzuncompress($str); +			if($page->getEnableStateValidation()) +			{ +				if(($str=$sm->validateData($str))!==false) +					return Prado::unserialize($str); +			} +			else +				return $str; +		} +		return null; +	} +} +class TOutputCache extends TControl implements INamingContainer +{ +	const CACHE_ID_PREFIX='prado:outputcache'; +	private $_cacheModuleID=''; +	private $_dataCached=false; +	private $_cacheAvailable=false; +	private $_cacheChecked=false; +	private $_cacheKey=null; +	private $_duration=60; +	private $_cache=null; +	private $_contents; +	private $_state; +	private $_actions=array(); +	private $_varyByParam=''; +	private $_keyPrefix=''; +	private $_varyBySession=false; +	private $_cachePostBack=false; +	private $_cacheTime=0; +	public function getAllowChildControls() +	{ +		$this->determineCacheability(); +		return !$this->_dataCached; +	} +	private function determineCacheability() +	{ +		if(!$this->_cacheChecked) +		{ +			$this->_cacheChecked=true; +			if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack())) +			{ +				if($this->_cacheModuleID!=='') +				{ +					$this->_cache=$this->getApplication()->getModule($this->_cacheModuleID); +					if(!($this->_cache instanceof ICache)) +						throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID); +				} +				else +					$this->_cache=$this->getApplication()->getCache(); +				if($this->_cache!==null) +				{ +					$this->_cacheAvailable=true; +					$data=$this->_cache->get($this->getCacheKey()); +					if(is_array($data)) +					{ +						$param=new TOutputCacheCheckDependencyEventParameter; +						$param->setCacheTime(isset($data[3])?$data[3]:0); +						$this->onCheckDependency($param); +						$this->_dataCached=$param->getIsValid(); +					} +					else +						$this->_dataCached=false; +					if($this->_dataCached) +						list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data; +				} +			} +		} +	} +	protected function initRecursive($namingContainer=null) +	{ +		if($this->_cacheAvailable && !$this->_dataCached) +		{ +			$stack=$this->getPage()->getCachingStack(); +			$stack->push($this); +			parent::initRecursive($namingContainer); +			$stack->pop(); +		} +		else +			parent::initRecursive($namingContainer); +	} +	protected function loadRecursive() +	{ +		if($this->_cacheAvailable && !$this->_dataCached) +		{ +			$stack=$this->getPage()->getCachingStack(); +			$stack->push($this); +			parent::loadRecursive(); +			$stack->pop(); +		} +		else +		{ +			if($this->_dataCached) +				$this->performActions(); +			parent::loadRecursive(); +		} +	} +	private function performActions() +	{ +		$page=$this->getPage(); +		$cs=$page->getClientScript(); +		foreach($this->_actions as $action) +		{ +			if($action[0]==='Page.ClientScript') +				call_user_func_array(array($cs,$action[1]),$action[2]); +			else if($action[0]==='Page') +				call_user_func_array(array($page,$action[1]),$action[2]); +			else +				call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]); +		} +	} +	protected function preRenderRecursive() +	{ +		if($this->_cacheAvailable && !$this->_dataCached) +		{ +			$stack=$this->getPage()->getCachingStack(); +			$stack->push($this); +			parent::preRenderRecursive(); +			$stack->pop(); +		} +		else +			parent::preRenderRecursive(); +	} +	protected function loadStateRecursive(&$state,$needViewState=true) +	{ +		$st=unserialize($state); +		parent::loadStateRecursive($st,$needViewState); +	} +	protected function &saveStateRecursive($needViewState=true) +	{ +		if($this->_dataCached) +			return $this->_state; +		else +		{ +			$st=parent::saveStateRecursive($needViewState); +			$this->_state=serialize($st); +			return $this->_state; +		} +	} +	public function registerAction($context,$funcName,$funcParams) +	{ +		$this->_actions[]=array($context,$funcName,$funcParams); +	} +	private function getCacheKey() +	{ +		if($this->_cacheKey===null) +			$this->_cacheKey=$this->calculateCacheKey(); +		return $this->_cacheKey; +	} +	protected function calculateCacheKey() +	{ +		$key=$this->getBaseCacheKey(); +		if($this->_varyBySession) +			$key.=$this->getSession()->getSessionID(); +		if($this->_varyByParam!=='') +		{ +			$params=array(); +			$request=$this->getRequest(); +			foreach(explode(',',$this->_varyByParam) as $name) +			{ +				$name=trim($name); +				$params[$name]=$request->itemAt($name); +			} +			$key.=serialize($params); +		} +		$param=new TOutputCacheCalculateKeyEventParameter; +		$this->onCalculateKey($param); +		$key.=$param->getCacheKey(); +		return $key; +	} +	protected function getBaseCacheKey() +	{ +		return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID(); +	} +	public function getCacheModuleID() +	{ +		return $this->_cacheModuleID; +	} +	public function setCacheModuleID($value) +	{ +		$this->_cacheModuleID=$value; +	} +	public function setCacheKeyPrefix($value) +	{ +		$this->_keyPrefix=$value; +	} +	public function getCacheTime() +	{ +		return $this->_cacheTime; +	} +	protected function getCacheDependency() +	{ +		return null; +	} +	public function getContentCached() +	{ +		return $this->_dataCached; +	} +	public function getDuration() +	{ +		return $this->_duration; +	} +	public function setDuration($value) +	{ +		if(($value=TPropertyValue::ensureInteger($value))<0) +			throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this)); +		$this->_duration=$value; +	} +	public function getVaryByParam() +	{ +		return $this->_varyByParam; +	} +	public function setVaryByParam($value) +	{ +		$this->_varyByParam=trim($value); +	} +	public function getVaryBySession() +	{ +		return $this->_varyBySession; +	} +	public function setVaryBySession($value) +	{ +		$this->_varyBySession=TPropertyValue::ensureBoolean($value); +	} +	public function getCachingPostBack() +	{ +		return $this->_cachePostBack; +	} +	public function setCachingPostBack($value) +	{ +		$this->_cachePostBack=TPropertyValue::ensureBoolean($value); +	} +	public function onCheckDependency($param) +	{ +		$this->raiseEvent('OnCheckDependency',$this,$param); +	} +	public function onCalculateKey($param) +	{ +		$this->raiseEvent('OnCalculateKey',$this,$param); +	} +	public function render($writer) +	{ +		if($this->_dataCached) +			$writer->write($this->_contents); +		else if($this->_cacheAvailable) +		{ +			$textWriter=new TTextWriter; +			$stack=$this->getPage()->getCachingStack(); +			$stack->push($this); +			parent::render(new THtmlWriter($textWriter)); +			$stack->pop(); +			$content=$textWriter->flush(); +			$data=array($content,$this->_state,$this->_actions,time()); +			$this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency()); +			$writer->write($content); +		} +		else +			parent::render($writer); +	} +} +class TOutputCacheCheckDependencyEventParameter extends TEventParameter +{ +	private $_isValid=true; +	private $_cacheTime=0; +	public function getIsValid() +	{ +		return $this->_isValid; +	} +	public function setIsValid($value) +	{ +		$this->_isValid=TPropertyValue::ensureBoolean($value); +	} +	public function getCacheTime() +	{ +		return $this->_cacheTime; +	} +	public function setCacheTime($value) +	{ +		$this->_cacheTime=TPropertyValue::ensureInteger($value); +	} +} +class TOutputCacheCalculateKeyEventParameter extends TEventParameter +{ +	private $_cacheKey=''; +	public function getCacheKey() +	{ +		return $this->_cacheKey; +	} +	public function setCacheKey($value) +	{ +		$this->_cacheKey=TPropertyValue::ensureString($value); +	} +} +class TTemplateManager extends TModule +{ +	const TEMPLATE_FILE_EXT='.tpl'; +	const TEMPLATE_CACHE_PREFIX='prado:template:'; +	public function init($config) +	{ +		$this->getService()->setTemplateManager($this); +	} +	public function getTemplateByClassName($className) +	{ +		$class=new ReflectionClass($className); +		$tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT; +		return $this->getTemplateByFileName($tplFile); +	} +	public function getTemplateByFileName($fileName) +	{ +		if(($fileName=$this->getLocalizedTemplate($fileName))!==null) +		{ +			if(($cache=$this->getApplication()->getCache())===null) +				return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName); +			else +			{ +				$array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName); +				if(is_array($array)) +				{ +					list($template,$timestamps)=$array; +					if($this->getApplication()->getMode()===TApplicationMode::Performance) +						return $template; +					$cacheValid=true; +					foreach($timestamps as $tplFile=>$timestamp) +					{ +						if(!is_file($tplFile) || filemtime($tplFile)>$timestamp) +						{ +							$cacheValid=false; +							break; +						} +					} +					if($cacheValid) +						return $template; +				} +				$template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName); +				$includedFiles=$template->getIncludedFiles(); +				$timestamps=array(); +				$timestamps[$fileName]=filemtime($fileName); +				foreach($includedFiles as $includedFile) +					$timestamps[$includedFile]=filemtime($includedFile); +				$cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps)); +				return $template; +			} +		} +		else +			return null; +	} +	protected function getLocalizedTemplate($filename) +	{ +		if(($app=$this->getApplication()->getGlobalization(false))===null) +			return is_file($filename)?$filename:null; +		foreach($app->getLocalizedResource($filename) as $file) +		{ +			if(($file=realpath($file))!==false && is_file($file)) +				return $file; +		} +		return null; +	} +} +class TTemplate extends TApplicationComponent implements ITemplate +{ +	const REGEX_RULES='/<!--.*?--!>|<!---.*?--->|<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|<prop:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/>/msS'; +	const CONFIG_DATABIND=0; +	const CONFIG_EXPRESSION=1; +	const CONFIG_ASSET=2; +	const CONFIG_PARAMETER=3; +	const CONFIG_LOCALIZATION=4; +	const CONFIG_TEMPLATE=5; +	private $_tpl=array(); +	private $_directive=array(); +	private $_contextPath; +	private $_tplFile=null; +	private $_startingLine=0; +	private $_content; +	private $_sourceTemplate=true; +	private $_hashCode=''; +	private $_tplControl=null; +	private $_includedFiles=array(); +	private $_includeAtLine=array(); +	private $_includeLines=array(); +	public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true) +	{ +		$this->_sourceTemplate=$sourceTemplate; +		$this->_contextPath=$contextPath; +		$this->_tplFile=$tplFile; +		$this->_startingLine=$startingLine; +		$this->_content=$template; +		$this->_hashCode=md5($template); +		$this->parse($template); +		$this->_content=null;  +	} +	public function getTemplateFile() +	{ +		return $this->_tplFile; +	} +	public function getIsSourceTemplate() +	{ +		return $this->_sourceTemplate; +	} +	public function getContextPath() +	{ +		return $this->_contextPath; +	} +	public function getDirective() +	{ +		return $this->_directive; +	} +	public function getHashCode() +	{ +		return $this->_hashCode; +	} +	public function &getItems() +	{ +		return $this->_tpl; +	} +	public function instantiateIn($tplControl,$parentControl=null) +	{ +		$this->_tplControl=$tplControl; +		if($parentControl===null) +			$parentControl=$tplControl; +		if(($page=$tplControl->getPage())===null) +			$page=$this->getService()->getRequestedPage(); +		$controls=array(); +		$directChildren=array(); +		foreach($this->_tpl as $key=>$object) +		{ +			if($object[0]===-1) +				$parent=$parentControl; +			else if(isset($controls[$object[0]])) +				$parent=$controls[$object[0]]; +			else +				continue; +			if(isset($object[2]))	 +			{ +				$component=Prado::createComponent($object[1]); +				$properties=&$object[2]; +				if($component instanceof TControl) +				{ +					if($component instanceof TOutputCache) +						$component->setCacheKeyPrefix($this->_hashCode.$key); +					$component->setTemplateControl($tplControl); +					if(isset($properties['id'])) +					{ +						if(is_array($properties['id'])) +							$properties['id']=$component->evaluateExpression($properties['id'][1]); +						$tplControl->registerObject($properties['id'],$component); +					} +					if(isset($properties['skinid'])) +					{ +						if(is_array($properties['skinid'])) +							$component->setSkinID($component->evaluateExpression($properties['skinid'][1])); +						else +							$component->setSkinID($properties['skinid']); +						unset($properties['skinid']); +					} +					$component->trackViewState(false); +					$component->applyStyleSheetSkin($page); +					foreach($properties as $name=>$value) +						$this->configureControl($component,$name,$value); +					$component->trackViewState(true); +					if($parent===$parentControl) +						$directChildren[]=$component; +					else +						$component->createdOnTemplate($parent); +					if($component->getAllowChildControls()) +						$controls[$key]=$component; +				} +				else if($component instanceof TComponent) +				{ +					$controls[$key]=$component; +					if(isset($properties['id'])) +					{ +						if(is_array($properties['id'])) +							$properties['id']=$component->evaluateExpression($properties['id'][1]); +						$tplControl->registerObject($properties['id'],$component); +						if(!$component->hasProperty('id')) +							unset($properties['id']); +					} +					foreach($properties as $name=>$value) +						$this->configureComponent($component,$name,$value); +					if($parent===$parentControl) +						$directChildren[]=$component; +					else +						$component->createdOnTemplate($parent); +				} +			} +			else +			{ +				if($object[1] instanceof TCompositeLiteral) +				{ +					$o=clone $object[1]; +					$o->setContainer($tplControl); +					if($parent===$parentControl) +						$directChildren[]=$o; +					else +						$parent->addParsedObject($o); +				} +				else +				{ +					if($parent===$parentControl) +						$directChildren[]=$object[1]; +					else +						$parent->addParsedObject($object[1]); +				} +			} +		} +		foreach($directChildren as $control) +		{ +			if($control instanceof TComponent) +				$control->createdOnTemplate($parentControl); +			else +				$parentControl->addParsedObject($control); +		} +	} +	protected function configureControl($control,$name,$value) +	{ +		if(strncasecmp($name,'on',2)===0)		 +			$this->configureEvent($control,$name,$value,$control); +		else if(($pos=strrpos($name,'.'))===false)	 +			$this->configureProperty($control,$name,$value); +		else	 +			$this->configureSubProperty($control,$name,$value); +	} +	protected function configureComponent($component,$name,$value) +	{ +		if(strpos($name,'.')===false)	 +			$this->configureProperty($component,$name,$value); +		else	 +			$this->configureSubProperty($component,$name,$value); +	} +	protected function configureEvent($control,$name,$value,$contextControl) +	{ +		if(strpos($value,'.')===false) +			$control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value)); +		else +			$control->attachEventHandler($name,array($contextControl,$value)); +	} +	protected function configureProperty($component,$name,$value) +	{ +		if(is_array($value)) +		{ +			switch($value[0]) +			{ +				case self::CONFIG_DATABIND: +					$component->bindProperty($name,$value[1]); +					break; +				case self::CONFIG_EXPRESSION: +					if($component instanceof TControl) +						$component->autoBindProperty($name,$value[1]); +					else +					{ +						$setter='set'.$name; +						$component->$setter($this->_tplControl->evaluateExpression($value[1])); +					} +					break; +				case self::CONFIG_TEMPLATE: +					$setter='set'.$name; +					$component->$setter($value[1]); +					break; +				case self::CONFIG_ASSET:		 +					$setter='set'.$name; +					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]); +					$component->$setter($url); +					break; +				case self::CONFIG_PARAMETER:		 +					$setter='set'.$name; +					$component->$setter($this->getApplication()->getParameters()->itemAt($value[1])); +					break; +				case self::CONFIG_LOCALIZATION: +					$setter='set'.$name; +					$component->$setter(Prado::localize($value[1])); +					break; +				default:	 +					throw new TConfigurationException('template_tag_unexpected',$name,$value[1]); +					break; +			} +		} +		else +		{ +			$setter='set'.$name; +			$component->$setter($value); +		} +	} +	protected function configureSubProperty($component,$name,$value) +	{ +		if(is_array($value)) +		{ +			switch($value[0]) +			{ +				case self::CONFIG_DATABIND:		 +					$component->bindProperty($name,$value[1]); +					break; +				case self::CONFIG_EXPRESSION:		 +					if($component instanceof TControl) +						$component->autoBindProperty($name,$value[1]); +					else +						$component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1])); +					break; +				case self::CONFIG_TEMPLATE: +					$component->setSubProperty($name,$value[1]); +					break; +				case self::CONFIG_ASSET:		 +					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]); +					$component->setSubProperty($name,$url); +					break; +				case self::CONFIG_PARAMETER:		 +					$component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1])); +					break; +				case self::CONFIG_LOCALIZATION: +					$component->setSubProperty($name,Prado::localize($value[1])); +					break; +				default:	 +					throw new TConfigurationException('template_tag_unexpected',$name,$value[1]); +					break; +			} +		} +		else +			$component->setSubProperty($name,$value); +	} +	protected function parse($input) +	{ +		$input=$this->preprocess($input); +		$tpl=&$this->_tpl; +		$n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE); +		$expectPropEnd=false; +		$textStart=0; +        $stack=array(); +		$container=-1; +		$matchEnd=0; +		$c=0; +		$this->_directive=null; +		try +		{ +			for($i=0;$i<$n;++$i) +			{ +				$match=&$matches[$i]; +				$str=$match[0][0]; +				$matchStart=$match[0][1]; +				$matchEnd=$matchStart+strlen($str)-1; +				if(strpos($str,'<com:')===0)	 +				{ +					if($expectPropEnd) +						continue; +					if($matchStart>$textStart) +						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); +					$textStart=$matchEnd+1; +					$type=$match[1][0]; +					$attributes=$this->parseAttributes($match[2][0],$match[2][1]); +					$this->validateAttributes($type,$attributes); +					$tpl[$c++]=array($container,$type,$attributes); +					if($str[strlen($str)-2]!=='/')   +					{ +						$stack[] = $type; +						$container=$c-1; +					} +				} +				else if(strpos($str,'</com:')===0)	 +				{ +					if($expectPropEnd) +						continue; +					if($matchStart>$textStart) +						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); +					$textStart=$matchEnd+1; +					$type=$match[1][0]; +					if(empty($stack)) +						throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>"); +					$name=array_pop($stack); +					if($name!==$type) +					{ +						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>"; +						throw new TConfigurationException('template_closingtag_expected',$tag); +					} +					$container=$tpl[$container][0]; +				} +				else if(strpos($str,'<%@')===0)	 +				{ +					if($expectPropEnd) +						continue; +					if($matchStart>$textStart) +						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); +					$textStart=$matchEnd+1; +					if(isset($tpl[0]) || $this->_directive!==null) +						throw new TConfigurationException('template_directive_nonunique'); +					$this->_directive=$this->parseAttributes($match[4][0],$match[4][1]); +				} +				else if(strpos($str,'<%')===0)	 +				{ +					if($expectPropEnd) +						continue; +					if($matchStart>$textStart) +						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); +					$textStart=$matchEnd+1; +					$literal=trim($match[5][0]); +					if($str[2]==='=')	 +						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal)); +					else if($str[2]==='%')   +						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal)); +					else if($str[2]==='#') +						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal)); +					else if($str[2]==='$') +						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')")); +					else if($str[2]==='~') +						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')")); +					else if($str[2]==='/') +						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'")); +					else if($str[2]==='[') +					{ +						$literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\")); +						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')")); +					} +				} +				else if(strpos($str,'<prop:')===0)	 +				{ +					if(strrpos($str,'/>')===strlen($str)-2)   +					{ +						if($expectPropEnd) +							continue; +						if($matchStart>$textStart) +							$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); +						$textStart=$matchEnd+1; +						$prop=strtolower($match[6][0]); +						$attrs=$this->parseAttributes($match[7][0],$match[7][1]); +						$attributes=array(); +						foreach($attrs as $name=>$value) +							$attributes[$prop.'.'.$name]=$value; +						$type=$tpl[$container][1]; +						$this->validateAttributes($type,$attributes); +						foreach($attributes as $name=>$value) +						{ +							if(isset($tpl[$container][2][$name])) +								throw new TConfigurationException('template_property_duplicated',$name); +							$tpl[$container][2][$name]=$value; +						} +					} +					else   +					{ +						$prop=strtolower($match[3][0]); +						$stack[] = '@'.$prop; +						if(!$expectPropEnd) +						{ +							if($matchStart>$textStart) +								$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); +							$textStart=$matchEnd+1; +							$expectPropEnd=true; +						} +					} +				} +				else if(strpos($str,'</prop:')===0)	 +				{ +					$prop=strtolower($match[3][0]); +					if(empty($stack)) +						throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>"); +					$name=array_pop($stack); +					if($name!=='@'.$prop) +					{ +						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>"; +						throw new TConfigurationException('template_closingtag_expected',$tag); +					} +					if(($last=count($stack))<1 || $stack[$last-1][0]!=='@') +					{ +						if($matchStart>$textStart) +						{ +							$value=substr($input,$textStart,$matchStart-$textStart); +							if(substr($prop,-8,8)==='template') +								$value=$this->parseTemplateProperty($value,$textStart); +							else +								$value=$this->parseAttribute($value); +							if($container>=0) +							{ +								$type=$tpl[$container][1]; +								$this->validateAttributes($type,array($prop=>$value)); +								if(isset($tpl[$container][2][$prop])) +									throw new TConfigurationException('template_property_duplicated',$prop); +								$tpl[$container][2][$prop]=$value; +							} +							else	 +								$this->_directive[$prop]=$value; +							$textStart=$matchEnd+1; +						} +						$expectPropEnd=false; +					} +				} +				else if(strpos($str,'<!--')===0)	 +				{ +					if($expectPropEnd) +						throw new TConfigurationException('template_comments_forbidden'); +					if($matchStart>$textStart) +						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); +					$textStart=$matchEnd+1; +				} +				else +					throw new TConfigurationException('template_matching_unexpected',$match); +			} +			if(!empty($stack)) +			{ +				$name=array_pop($stack); +				$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>"; +				throw new TConfigurationException('template_closingtag_expected',$tag); +			} +			if($textStart<strlen($input)) +				$tpl[$c++]=array($container,substr($input,$textStart)); +		} +		catch(Exception $e) +		{ +			if(($e instanceof TException) && ($e instanceof TTemplateException)) +				throw $e; +			if($matchEnd===0) +				$line=$this->_startingLine+1; +			else +				$line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1))); +			$this->handleException($e,$line,$input); +		} +		if($this->_directive===null) +			$this->_directive=array(); +		$objects=array(); +		$parent=null; +		$merged=array(); +		foreach($tpl as $id=>$object) +		{ +			if(isset($object[2]) || $object[0]!==$parent) +			{ +				if($parent!==null) +				{ +					if(count($merged[1])===1 && is_string($merged[1][0])) +						$objects[$id-1]=array($merged[0],$merged[1][0]); +					else +						$objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1])); +				} +				if(isset($object[2])) +				{ +					$parent=null; +					$objects[$id]=$object; +				} +				else +				{ +					$parent=$object[0]; +					$merged=array($parent,array($object[1])); +				} +			} +			else +				$merged[1][]=$object[1]; +		} +		if($parent!==null) +		{ +			if(count($merged[1])===1 && is_string($merged[1][0])) +				$objects[$id]=array($merged[0],$merged[1][0]); +			else +				$objects[$id]=array($merged[0],new TCompositeLiteral($merged[1])); +		} +		$tpl=$objects; +		return $objects; +	} +	protected function parseAttributes($str,$offset) +	{ +		if($str==='') +			return array(); +		$pattern='/([\w\.]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS'; +		$attributes=array(); +		$n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE); +		for($i=0;$i<$n;++$i) +		{ +			$match=&$matches[$i]; +			$name=strtolower($match[1][0]); +			if(isset($attributes[$name])) +				throw new TConfigurationException('template_property_duplicated',$name); +			$value=$match[2][0]; +			if(substr($name,-8,8)==='template') +			{ +				if($value[0]==='\'' || $value[0]==='"') +					$attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1); +				else +					$attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]); +			} +			else +			{ +				if($value[0]==='\'' || $value[0]==='"') +					$attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2)); +				else +					$attributes[$name]=$this->parseAttribute($value); +			} +		} +		return $attributes; +	} +	protected function parseTemplateProperty($content,$offset) +	{ +		$line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1; +		return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false)); +	} +	protected function parseAttribute($value) +	{ +		if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0) +		{ +			$isDataBind=false; +			$textStart=0; +			$expr=''; +			for($i=0;$i<$n;++$i) +			{ +				$match=$matches[0][$i]; +				$token=$match[0]; +				$offset=$match[1]; +				$length=strlen($token); +				if($token[2]==='#') +					$isDataBind=true; +				if($offset>$textStart) +					$expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'"; +				$expr.='.('.substr($token,3,$length-5).')'; +				$textStart=$offset+$length; +			} +			$length=strlen($value); +			if($length>$textStart) +				$expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'"; +			if($isDataBind) +				return array(self::CONFIG_DATABIND,ltrim($expr,'.')); +			else +				return array(self::CONFIG_EXPRESSION,ltrim($expr,'.')); +		} +		else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>)\\s*/msS',$value,$matches) && $matches[0]===$value) +		{ +			$value=$matches[1]; +			if($value[2]==='~')  +				return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5))); +			else if($value[2]==='[') +				return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6))); +			else if($value[2]==='$') +				return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5))); +		} +		else +			return $value; +	} +	protected function validateAttributes($type,$attributes) +	{ +		Prado::using($type); +		if(($pos=strrpos($type,'.'))!==false) +			$className=substr($type,$pos+1); +		else +			$className=$type; +		$class=new TReflectionClass($className); +		if(is_subclass_of($className,'TControl') || $className==='TControl') +		{ +			foreach($attributes as $name=>$att) +			{ +				if(($pos=strpos($name,'.'))!==false) +				{ +					$subname=substr($name,0,$pos); +					if(!$class->hasMethod('get'.$subname)) +						throw new TConfigurationException('template_property_unknown',$type,$subname); +				} +				else if(strncasecmp($name,'on',2)===0) +				{ +					if(!$class->hasMethod($name)) +						throw new TConfigurationException('template_event_unknown',$type,$name); +					else if(!is_string($att)) +						throw new TConfigurationException('template_eventhandler_invalid',$type,$name); +				} +				else +				{ +					if(!$class->hasMethod('set'.$name)) +					{ +						if($class->hasMethod('get'.$name)) +							throw new TConfigurationException('template_property_readonly',$type,$name); +						else +							throw new TConfigurationException('template_property_unknown',$type,$name); +					} +					else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION) +					{ +						if(strcasecmp($name,'id')===0) +							throw new TConfigurationException('template_controlid_invalid',$type); +						else if(strcasecmp($name,'skinid')===0) +							throw new TConfigurationException('template_controlskinid_invalid',$type); +					} +				} +			} +		} +		else if(is_subclass_of($className,'TComponent') || $className==='TComponent') +		{ +			foreach($attributes as $name=>$att) +			{ +				if(is_array($att) && ($att[0]===self::CONFIG_DATABIND)) +					throw new TConfigurationException('template_databind_forbidden',$type,$name); +				if(($pos=strpos($name,'.'))!==false) +				{ +					$subname=substr($name,0,$pos); +					if(!$class->hasMethod('get'.$subname)) +						throw new TConfigurationException('template_property_unknown',$type,$subname); +				} +				else if(strncasecmp($name,'on',2)===0) +					throw new TConfigurationException('template_event_forbidden',$type,$name); +				else +				{ +					if(strcasecmp($name,'id')!==0 && !$class->hasMethod('set'.$name)) +					{ +						if($class->hasMethod('get'.$name)) +							throw new TConfigurationException('template_property_readonly',$type,$name); +						else +							throw new TConfigurationException('template_property_unknown',$type,$name); +					} +				} +			} +		} +		else +			throw new TConfigurationException('template_component_required',$type); +	} +	public function getIncludedFiles() +	{ +		return $this->_includedFiles; +	} +	protected function handleException($e,$line,$input=null) +	{ +		$srcFile=$this->_tplFile; +		if(($n=count($this->_includedFiles))>0)  +		{ +			for($i=$n-1;$i>=0;--$i) +			{ +				if($this->_includeAtLine[$i]<=$line) +				{ +					if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i]) +					{ +						$line=$line-$this->_includeAtLine[$i]+1; +						$srcFile=$this->_includedFiles[$i]; +						break; +					} +					else +						$line=$line-$this->_includeLines[$i]+1; +				} +			} +		} +		$exception=new TTemplateException('template_format_invalid',$e->getMessage()); +		$exception->setLineNumber($line); +		if(!empty($srcFile)) +			$exception->setTemplateFile($srcFile); +		else +			$exception->setTemplateSource($input); +		throw $exception; +	} +	protected function preprocess($input) +	{ +		if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE)) +		{ +			for($i=0;$i<$n;++$i) +			{ +				$filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT); +				if($filePath!==null && is_file($filePath)) +					$this->_includedFiles[]=$filePath; +				else +				{ +					$errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1))); +					$this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input); +				} +			} +			$base=0; +			for($i=0;$i<$n;++$i) +			{ +				$ext=file_get_contents($this->_includedFiles[$i]); +				$length=strlen($matches[$i][0][0]); +				$offset=$base+$matches[$i][0][1]; +				$this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset))); +				$this->_includeLines[$i]=count(explode("\n",$ext)); +				$input=substr_replace($input,$ext,$offset,$length); +				$base+=strlen($ext)-$length; +			} +		} +		return $input; +	} +} +class TThemeManager extends TModule +{ +	const DEFAULT_BASEPATH='themes'; +	private $_initialized=false; +	private $_basePath=null; +	private $_baseUrl=null; +	public function init($config) +	{ +		$this->_initialized=true; +		$service=$this->getService(); +		if($service instanceof TPageService) +			$service->setThemeManager($this); +		else +			throw new TConfigurationException('thememanager_service_unavailable'); +	} +	public function getTheme($name) +	{ +		$themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name; +		$themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name; +		return new TTheme($themePath,$themeUrl); +	} +	public function getAvailableThemes() +	{ +		$themes=array(); +		$basePath=$this->getBasePath(); +		$folder=@opendir($basePath); +		while($file=@readdir($folder)) +		{ +			if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file)) +				$themes[]=$file; +		} +		closedir($folder); +		return $themes; +	} +	public function getBasePath() +	{ +		if($this->_basePath===null) +		{ +			$this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH; +			if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath)) +				throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath); +			$this->_basePath=$basePath; +		} +		return $this->_basePath; +	} +	public function setBasePath($value) +	{ +		if($this->_initialized) +			throw new TInvalidOperationException('thememanager_basepath_unchangeable'); +		else +		{ +			$this->_basePath=Prado::getPathOfNamespace($value); +			if($this->_basePath===null || !is_dir($this->_basePath)) +				throw new TInvalidDataValueException('thememanager_basepath_invalid',$value); +		} +	} +	public function getBaseUrl() +	{ +		if($this->_baseUrl===null) +		{ +			$appPath=dirname($this->getRequest()->getApplicationFilePath()); +			$basePath=$this->getBasePath(); +			if(strpos($basePath,$appPath)===false) +				throw new TConfigurationException('thememanager_baseurl_required'); +			$appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\'); +			$this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/'); +		} +		return $this->_baseUrl; +	} +	public function setBaseUrl($value) +	{ +		$this->_baseUrl=rtrim($value,'/'); +	} +} +class TTheme extends TApplicationComponent implements ITheme +{ +	const THEME_CACHE_PREFIX='prado:theme:'; +	const SKIN_FILE_EXT='.skin'; +	private $_themePath; +	private $_themeUrl; +	private $_skins=null; +	private $_name=''; +	private $_cssFiles=array(); +	private $_jsFiles=array(); +	public function __construct($themePath,$themeUrl) +	{ +		$this->_themeUrl=$themeUrl; +		$this->_themePath=realpath($themePath); +		$this->_name=basename($themePath); +		$cacheValid=false; +		if(($cache=$this->getApplication()->getCache())!==null) +		{ +			$array=$cache->get(self::THEME_CACHE_PREFIX.$themePath); +			if(is_array($array)) +			{ +				list($skins,$cssFiles,$jsFiles,$timestamp)=$array; +				if($this->getApplication()->getMode()!==TApplicationMode::Performance) +				{ +					if(($dir=opendir($themePath))===false) +						throw new TIOException('theme_path_inexistent',$themePath); +					$cacheValid=true; +					while(($file=readdir($dir))!==false) +					{ +						if($file==='.' || $file==='..') +							continue; +						else if(basename($file,'.css')!==$file) +							$this->_cssFiles[]=$themeUrl.'/'.$file; +						else if(basename($file,'.js')!==$file) +							$this->_jsFiles[]=$themeUrl.'/'.$file; +						else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp) +						{ +							$cacheValid=false; +							break; +						} +					} +					closedir($dir); +					if($cacheValid) +						$this->_skins=$skins; +				} +				else +				{ +					$cacheValid=true; +					$this->_cssFiles=$cssFiles; +					$this->_jsFiles=$jsFiles; +					$this->_skins=$skins; +				} +			} +		} +		if(!$cacheValid) +		{ +			$this->_cssFiles=array(); +			$this->_jsFiles=array(); +			$this->_skins=array(); +			if(($dir=opendir($themePath))===false) +				throw new TIOException('theme_path_inexistent',$themePath); +			while(($file=readdir($dir))!==false) +			{ +				if($file==='.' || $file==='..') +					continue; +				else if(basename($file,'.css')!==$file) +					$this->_cssFiles[]=$themeUrl.'/'.$file; +				else if(basename($file,'.js')!==$file) +					$this->_jsFiles[]=$themeUrl.'/'.$file; +				else if(basename($file,self::SKIN_FILE_EXT)!==$file) +				{ +					$template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file); +					foreach($template->getItems() as $skin) +					{ +						if(!isset($skin[2]))   +							continue; +						else if($skin[0]!==-1) +							throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath)); +						$type=$skin[1]; +						$id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0; +						unset($skin[2]['skinid']); +						if(isset($this->_skins[$type][$id])) +							throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath)); +						$this->_skins[$type][$id]=$skin[2]; +					} +				} +			} +			closedir($dir); +			sort($this->_cssFiles); +			sort($this->_jsFiles); +			if($cache!==null) +				$cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time())); +		} +	} +	public function getName() +	{ +		return $this->_name; +	} +	protected function setName($value) +	{ +		$this->_name = $value; +	} +	public function getBaseUrl() +	{ +		return $this->_themeUrl; +	} +	protected function setBaseUrl($value) +	{ +		$this->_themeUrl=rtrim($value,'/'); +	} +	public function getBasePath() +	{ +		return $this->_themePath; +	} +	protected function setBasePath($value) +	{ +		$this->_themePath=$value; +	} +	public function getSkins() +	{ +		return $this->_skins; +	} +	protected function setSkins($value) +	{ +		$this->_skins = $value; +	} +	public function applySkin($control) +	{ +		$type=get_class($control); +		if(($id=$control->getSkinID())==='') +			$id=0; +		if(isset($this->_skins[$type][$id])) +		{ +			foreach($this->_skins[$type][$id] as $name=>$value) +			{ +				if(is_array($value)) +				{ +					switch($value[0]) +					{ +						case TTemplate::CONFIG_EXPRESSION: +							$value=$this->evaluateExpression($value[1]); +							break; +						case TTemplate::CONFIG_ASSET: +							$value=$this->_themeUrl.'/'.ltrim($value[1],'/'); +							break; +						case TTemplate::CONFIG_DATABIND: +							$control->bindProperty($name,$value[1]); +							break; +						case TTemplate::CONFIG_PARAMETER: +							$control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1])); +							break; +						case TTemplate::CONFIG_TEMPLATE: +							$control->setSubProperty($name,$value[1]); +							break; +						case TTemplate::CONFIG_LOCALIZATION: +							$control->setSubProperty($name,Prado::localize($value[1])); +							break; +						default: +							throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]); +							break; +					} +				} +				if(!is_array($value)) +				{ +					if(strpos($name,'.')===false)	 +					{ +						if($control->hasProperty($name)) +						{ +							if($control->canSetProperty($name)) +							{ +								$setter='set'.$name; +								$control->$setter($value); +							} +							else +								throw new TConfigurationException('theme_property_readonly',$type,$name); +						} +						else +							throw new TConfigurationException('theme_property_undefined',$type,$name); +					} +					else	 +						$control->setSubProperty($name,$value); +				} +			} +			return true; +		} +		else +			return false; +	} +	public function getStyleSheetFiles() +	{ +		return $this->_cssFiles; +	} +	protected function setStyleSheetFiles($value) +	{ +		$this->_cssFiles=$value; +	} +	public function getJavaScriptFiles() +	{ +		return $this->_jsFiles; +	} +	protected function setJavaScriptFiles($value) +	{ +		$this->_jsFiles=$value; +	} +} +class TPageService extends TService +{ +	const CONFIG_FILE='config.xml'; +	const DEFAULT_BASEPATH='pages'; +	const CONFIG_CACHE_PREFIX='prado:pageservice:'; +	const PAGE_FILE_EXT='.page'; +	private $_basePath=null; +	private $_basePageClass='TPage'; +	private $_defaultPage='Home'; +	private $_pagePath=null; +	private $_page=null; +	private $_properties=array(); +	private $_initialized=false; +	private $_themeManager=null; +	private $_templateManager=null; +	public function init($config) +	{ +		$pageConfig=$this->loadPageConfig($config); +		$this->initPageContext($pageConfig); +		$this->_initialized=true; +	} +	protected function initPageContext($pageConfig) +	{ +		$application=$this->getApplication(); +		foreach($pageConfig->getApplicationConfigurations() as $appConfig) +			$application->applyConfiguration($appConfig); +		$this->applyConfiguration($pageConfig); +	} +	protected function applyConfiguration($config) +	{ +		$this->_properties=array_merge($this->_properties, $config->getProperties()); +		$this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules()); +		$pagePath=$this->getRequestedPagePath(); +		foreach($config->getExternalConfigurations() as $filePath=>$params) +		{ +			list($configPagePath,$condition)=$params; +			if($condition!==true) +				$condition=$this->evaluateExpression($condition); +			if($condition) +			{ +				if(($path=Prado::getPathOfNamespace($filePath,TApplication::CONFIG_FILE_EXT))===null || !is_file($path)) +					throw new TConfigurationException('pageservice_includefile_invalid',$filePath); +				$c=new TPageConfiguration($pagePath); +				$c->loadFromFile($path,$configPagePath); +				$this->applyConfiguration($c); +			} +		} +	} +	protected function determineRequestedPagePath() +	{ +		$pagePath=$this->getRequest()->getServiceParameter(); +		if(empty($pagePath)) +			$pagePath=$this->getDefaultPage(); +		return $pagePath; +	} +	protected function loadPageConfig($config) +	{ +		$application=$this->getApplication(); +		$pagePath=$this->getRequestedPagePath(); +		if(($cache=$application->getCache())===null) +		{ +			$pageConfig=new TPageConfiguration($pagePath); +			if($config!==null) +				$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),''); +			$pageConfig->loadFromFiles($this->getBasePath()); +		} +		else +		{ +			$configCached=true; +			$currentTimestamp=array(); +			$arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath); +			if(is_array($arr)) +			{ +				list($pageConfig,$timestamps)=$arr; +				if($application->getMode()!==TApplicationMode::Performance) +				{ +					foreach($timestamps as $fileName=>$timestamp) +					{ +						if($fileName===0)  +						{ +							$appConfigFile=$application->getConfigurationFile(); +							$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile); +							if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0])) +								$configCached=false; +						} +						else +						{ +							$currentTimestamp[$fileName]=@filemtime($fileName); +							if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName])) +								$configCached=false; +						} +					} +				} +			} +			else +			{ +				$configCached=false; +				$paths=explode('.',$pagePath); +				$configPath=$this->getBasePath(); +				foreach($paths as $path) +				{ +					$configFile=$configPath.DIRECTORY_SEPARATOR.self::CONFIG_FILE; +					$currentTimestamp[$configFile]=@filemtime($configFile); +					$configPath.=DIRECTORY_SEPARATOR.$path; +				} +				$appConfigFile=$application->getConfigurationFile(); +				$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile); +			} +			if(!$configCached) +			{ +				$pageConfig=new TPageConfiguration($pagePath); +				if($config!==null) +					$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),''); +				$pageConfig->loadFromFiles($this->getBasePath()); +				$cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp)); +			} +		} +		return $pageConfig; +	} +	public function getTemplateManager() +	{ +		if(!$this->_templateManager) +		{ +			$this->_templateManager=new TTemplateManager; +			$this->_templateManager->init(null); +		} +		return $this->_templateManager; +	} +	public function setTemplateManager(TTemplateManager $value) +	{ +		$this->_templateManager=$value; +	} +	public function getThemeManager() +	{ +		if(!$this->_themeManager) +		{ +			$this->_themeManager=new TThemeManager; +			$this->_themeManager->init(null); +		} +		return $this->_themeManager; +	} +	public function setThemeManager(TThemeManager $value) +	{ +		$this->_themeManager=$value; +	} +	public function getRequestedPagePath() +	{ +		if($this->_pagePath===null) +		{ +			$this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..'); +			if(empty($this->_pagePath)) +				throw new THttpException(404,'pageservice_page_required'); +		} +		return $this->_pagePath; +	} +	public function getRequestedPage() +	{ +		return $this->_page; +	} +	public function getDefaultPage() +	{ +		return $this->_defaultPage; +	} +	public function setDefaultPage($value) +	{ +		if($this->_initialized) +			throw new TInvalidOperationException('pageservice_defaultpage_unchangeable'); +		else +			$this->_defaultPage=$value; +	} +	public function getDefaultPageUrl() +	{ +		return $this->constructUrl($this->getDefaultPage()); +	} +	public function getBasePath() +	{ +		if($this->_basePath===null) +		{ +			$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH; +			if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath)) +				throw new TConfigurationException('pageservice_basepath_invalid',$basePath); +		} +		return $this->_basePath; +	} +	public function setBasePath($value) +	{ +		if($this->_initialized) +			throw new TInvalidOperationException('pageservice_basepath_unchangeable'); +		else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path)) +			throw new TConfigurationException('pageservice_basepath_invalid',$value); +		$this->_basePath=realpath($path); +	} +	public function setBasePageClass($value) +	{ +		$this->_basePageClass=$value; +	} +	public function getBasePageClass() +	{ +		return $this->_basePageClass; +	} +	public function run() +	{ +		$this->_page=$this->createPage($this->getRequestedPagePath()); +		$this->runPage($this->_page,$this->_properties); +	} +	protected function createPage($pagePath) +	{ +		$path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR); +		$hasTemplateFile=is_file($path.self::PAGE_FILE_EXT); +		$hasClassFile=is_file($path.Prado::CLASS_FILE_EXT); +		if(!$hasTemplateFile && !$hasClassFile) +			throw new THttpException(404,'pageservice_page_unknown',$pagePath); +		if($hasClassFile) +		{ +			$className=basename($path); +			if(!class_exists($className,false)) +				include_once($path.Prado::CLASS_FILE_EXT); +		} +		else +		{ +			$className=$this->getBasePageClass(); +			Prado::using($className); +			if(($pos=strrpos($className,'.'))!==false) +				$className=substr($className,$pos+1); +		} + 		if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage'))) +			throw new THttpException(404,'pageservice_page_unknown',$pagePath); +		$page=new $className; +		$page->setPagePath($pagePath); +		if($hasTemplateFile) +			$page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT)); +		return $page; +	} +	protected function runPage($page,$properties) +	{ +		foreach($properties as $name=>$value) +			$page->setSubProperty($name,$value); +		$page->run($this->getResponse()->createHtmlWriter()); +	} +	public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true) +	{ +		return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems); +	} +} +class TPageConfiguration extends TComponent +{ +	private $_appConfigs=array(); +	private $_properties=array(); +	private $_rules=array(); +	private $_includes=array(); +	private $_pagePath=''; +	public function __construct($pagePath) +	{ +		$this->_pagePath=$pagePath; +	} +	public function getExternalConfigurations() +	{ +		return $this->_includes; +	} +	public function getProperties() +	{ +		return $this->_properties; +	} +	public function getRules() +	{ +		return $this->_rules; +	} +	public function getApplicationConfigurations() +	{ +		return $this->_appConfigs; +	} +	public function loadFromFiles($basePath) +	{ +		$paths=explode('.',$this->_pagePath); +		$page=array_pop($paths); +		$path=$basePath; +		$configPagePath=''; +		foreach($paths as $p) +		{ +			$this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath); +			$path.=DIRECTORY_SEPARATOR.$p; +			if($configPagePath==='') +				$configPagePath=$p; +			else +				$configPagePath.='.'.$p; +		} +		$this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath); +		$this->_rules=new TAuthorizationRuleCollection($this->_rules); +	} +	public function loadFromFile($fname,$configPagePath) +	{ +		if(empty($fname) || !is_file($fname)) +			return; +		$dom=new TXmlDocument; +		if($dom->loadFromFile($fname)) +			$this->loadFromXml($dom,dirname($fname),$configPagePath); +		else +			throw new TConfigurationException('pageserviceconf_file_invalid',$fname); +	} +	public function loadFromXml($dom,$configPath,$configPagePath) +	{ +		$this->loadApplicationConfigurationFromXml($dom,$configPath); +		$this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath); +	} +	public function loadApplicationConfigurationFromXml($dom,$configPath) +	{ +		$appConfig=new TApplicationConfiguration; +		$appConfig->loadFromXml($dom,$configPath); +		$this->_appConfigs[]=$appConfig; +	} +	public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath) +	{ +		if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null) +		{ +			$rules=array(); +			foreach($authorizationNode->getElements() as $node) +			{ +				$patterns=$node->getAttribute('pages'); +				$ruleApplies=false; +				if(empty($patterns) || trim($patterns)==='*')  +					$ruleApplies=true; +				else +				{ +					foreach(explode(',',$patterns) as $pattern) +					{ +						if(($pattern=trim($pattern))!=='') +						{ +							if($configPagePath!=='')   +								$pattern=$configPagePath.'.'.$pattern; +							if(strcasecmp($pattern,$this->_pagePath)===0) +							{ +								$ruleApplies=true; +								break; +							} +							if($pattern[strlen($pattern)-1]==='*')  +							{ +								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0) +								{ +									$ruleApplies=true; +									break; +								} +							} +						} +					} +				} +				if($ruleApplies) +					$rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips')); +			} +			$this->_rules=array_merge($rules,$this->_rules); +		} +		if(($pagesNode=$dom->getElementByTagName('pages'))!==null) +		{ +			$this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray()); +			foreach($pagesNode->getElementsByTagName('page') as $node) +			{ +				$properties=$node->getAttributes(); +				$id=$properties->remove('id'); +				if(empty($id)) +					throw new TConfigurationException('pageserviceconf_page_invalid',$configPath); +				$matching=false; +				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id; +				if(strcasecmp($id,$this->_pagePath)===0) +					$matching=true; +				else if($id[strlen($id)-1]==='*')  +					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0; +				if($matching) +					$this->_properties=array_merge($this->_properties,$properties->toArray()); +			} +		} +		foreach($dom->getElementsByTagName('include') as $node) +		{ +			if(($when=$node->getAttribute('when'))===null) +				$when=true; +			if(($filePath=$node->getAttribute('file'))===null) +				throw new TConfigurationException('pageserviceconf_includefile_required'); +			if(isset($this->_includes[$filePath])) +				$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')'); +			else +				$this->_includes[$filePath]=array($configPagePath,$when); +		} +	} +} +class TAssetManager extends TModule +{ +	const DEFAULT_BASEPATH='assets'; +	private $_basePath=null; +	private $_baseUrl=null; +	private $_checkTimestamp=false; +	private $_application; +	private $_published=array(); +	private $_initialized=false; +	public function init($config) +	{ +		$application=$this->getApplication(); +		if($this->_basePath===null) +			$this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH; +		if(!is_writable($this->_basePath) || !is_dir($this->_basePath)) +			throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath); +		if($this->_baseUrl===null) +			$this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH; +		$application->setAssetManager($this); +		$this->_initialized=true; +	} +	public function getBasePath() +	{ +		return $this->_basePath; +	} +	public function setBasePath($value) +	{ +		if($this->_initialized) +			throw new TInvalidOperationException('assetmanager_basepath_unchangeable'); +		else +		{ +			$this->_basePath=Prado::getPathOfNamespace($value); +			if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath)) +				throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value); +		} +	} +	public function getBaseUrl() +	{ +		return $this->_baseUrl; +	} +	public function setBaseUrl($value) +	{ +		if($this->_initialized) +			throw new TInvalidOperationException('assetmanager_baseurl_unchangeable'); +		else +			$this->_baseUrl=rtrim($value,'/'); +	} +	public function publishFilePath($path,$checkTimestamp=false) +	{ +		if(isset($this->_published[$path])) +			return $this->_published[$path]; +		else if(empty($path) || ($fullpath=realpath($path))===false) +			throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path); +		else if(is_file($fullpath)) +		{ +			$dir=$this->hash(dirname($fullpath)); +			$fileName=basename($fullpath); +			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir; +			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance) +				$this->copyFile($fullpath,$dst); +			return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName; +		} +		else +		{ +			$dir=$this->hash($fullpath); +			if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance) +			{ +				$this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir); +			} +			return $this->_published[$path]=$this->_baseUrl.'/'.$dir; +		} +	} +	public function getPublishedPath($path) +	{ +		$path=realpath($path); +		if(is_file($path)) +			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path); +		else +			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path); +	} +	public function getPublishedUrl($path) +	{ +		$path=realpath($path); +		if(is_file($path)) +			return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path); +		else +			return $this->_baseUrl.'/'.$this->hash($path); +	} +	protected function hash($dir) +	{ +		return sprintf('%x',crc32($dir.Prado::getVersion())); +	} +	protected function copyFile($src,$dst) +	{ +		if(!is_dir($dst)) +		{ +			@mkdir($dst); +			@chmod($dst, PRADO_CHMOD); +		} +		$dstFile=$dst.DIRECTORY_SEPARATOR.basename($src); +		if(@filemtime($dstFile)<@filemtime($src)) +		{ +			@copy($src,$dstFile); +		} +	} +	public function copyDirectory($src,$dst) +	{ +		if(!is_dir($dst)) +		{ +			@mkdir($dst); +			@chmod($dst, PRADO_CHMOD); +		} +		if($folder=@opendir($src)) +		{ +			while($file=@readdir($folder)) +			{ +				if($file==='.' || $file==='..' || $file==='.svn') +					continue; +				else if(is_file($src.DIRECTORY_SEPARATOR.$file)) +				{ +					if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file)) +					{ +						@copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file); +						@chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);  +					} +				} +				else +					$this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file); +			} +			closedir($folder); +		} else { +			throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src); +		} +	} +	public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false) +	{ +		if(isset($this->_published[$md5sum])) +			return $this->_published[$md5sum]; +		else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath)) +			throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum); +		else +		{ +			$dir=$this->hash(dirname($fullpath)); +			$fileName=basename($fullpath); +			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir; +			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance) +			{ +				if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath)) +				{ +					$this->copyFile($fullpath,$dst); +					$this->deployTarFile($tarfile,$dst); +				} +			} +			return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir; +		} +	} +	protected function deployTarFile($path,$destination) +	{ +		if(($fullpath=realpath($path))===false || !is_file($fullpath)) +			throw new TIOException('assetmanager_tarfile_invalid',$path); +		else +		{ +			Prado::using('System.IO.TTarFileExtractor'); +			$tar = new TTarFileExtractor($fullpath); +			return $tar->extract($destination); +		} +	} +} +class TGlobalization extends TModule +{ +	private $_defaultCharset = 'UTF-8'; +	private $_defaultCulture = 'en'; +	private $_charset=null; +	private $_culture=null; +	private $_translation; +	public function init($xml) +	{ +		if($this->_charset===null) +			$this->_charset=$this->getDefaultCharset(); +		if($this->_culture===null) +			$this->_culture=$this->getDefaultCulture(); +		if($xml!==null) +		{ +			$translation = $xml->getElementByTagName('translation'); +			if($translation) +				$this->setTranslationConfiguration($translation->getAttributes()); +		} +		$this->getApplication()->setGlobalization($this); +	} +	public function getDefaultCulture() +	{ +		return $this->_defaultCulture; +	} +	public function setDefaultCulture($culture) +	{ +		$this->_defaultCulture = str_replace('-','_',$culture); +	} +	public function getDefaultCharset() +	{ +		return $this->_defaultCharset; +	} +	public function setDefaultCharset($charset) +	{ +		$this->_defaultCharset = $charset; +	} +	public function getCulture() +	{ +		return $this->_culture; +	} +	public function setCulture($culture) +	{ +		$this->_culture = str_replace('-','_',$culture); +	} +	public function getCharset() +	{ +		return $this->_charset; +	} +	public function setCharset($charset) +	{ +		$this->_charset = $charset; +	} +	public function getTranslationConfiguration() +	{ +		return $this->_translation; +	} +	protected function setTranslationConfiguration(TMap $config) +	{ +		if($config['type'] == 'XLIFF' || $config['type'] == 'gettext') +		{ +			if($config['source']) +			{ +				$config['source'] = Prado::getPathOfNamespace($config['source']); +				if(!is_dir($config['source'])) +				{ +					if(@mkdir($config['source'])===false) +					throw new TConfigurationException('globalization_source_path_failed', +						$config['source']); +					chmod($config['source'], PRADO_CHMOD);  +				} +			} +			else +			{ +				throw new TConfigurationException("invalid source dir '{$config['source']}'"); +			} +		} +		if($config['cache']) +		{ +			$config['cache'] = $this->getApplication()->getRunTimePath().'/i18n'; +			if(!is_dir($config['cache'])) +			{ +				if(@mkdir($config['cache'])===false) +					throw new TConfigurationException('globalization_cache_path_failed', +						$config['cache']); +				chmod($config['cache'], PRADO_CHMOD);  +			} +		} +		$this->_translation = $config; +	} +	public function getTranslationCatalogue() +	{ +		return $this->_translation['catalogue']; +	} +	public function setTranslationCatalogue($value) +	{ +		$this->_translation['catalogue'] = $value; +	} +	public function getCultureVariants($culture=null) +	{ +		if($culture===null) $culture = $this->getCulture(); +		$variants = explode('_', $culture); +		$result = array(); +		for(; count($variants) > 0; array_pop($variants)) +			$result[] = implode('_', $variants); +		return $result; +	} +	public function getLocalizedResource($file,$culture=null) +	{ +		$files = array(); +		$variants = $this->getCultureVariants($culture); +		$path = pathinfo($file); +		foreach($variants as $variant) +			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename']; +		$filename = substr($path['basename'],0,strrpos($path['basename'],'.')); +		foreach($variants as $variant) +			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension']; +		$files[] = $file; +		return $files; +	} +} +class TApplication extends TComponent +{ +	const STATE_OFF='Off'; +	const STATE_DEBUG='Debug'; +	const STATE_NORMAL='Normal'; +	const STATE_PERFORMANCE='Performance'; +	const PAGE_SERVICE_ID='page'; +	const CONFIG_FILE='application.xml'; +	const CONFIG_FILE_EXT='.xml'; +	const RUNTIME_PATH='runtime'; +	const CONFIGCACHE_FILE='config.cache'; +	const GLOBAL_FILE='global.cache'; +	private static $_steps=array( +		'onBeginRequest', +		'onLoadState', +		'onLoadStateComplete', +		'onAuthentication', +		'onAuthenticationComplete', +		'onAuthorization', +		'onAuthorizationComplete', +		'onPreRunService', +		'runService', +		'onSaveState', +		'onSaveStateComplete', +		'onPreFlushOutput', +		'flushOutput' +	); +	private $_id; +	private $_uniqueID; +	private $_requestCompleted=false; +	private $_step; +	private $_services; +	private $_service; +	private $_modules=array(); +	private $_parameters; +	private $_configFile; +	private $_basePath; +	private $_runtimePath; +	private $_stateChanged=false; +	private $_globals=array(); +	private $_cacheFile; +	private $_errorHandler; +	private $_request; +	private $_response; +	private $_session; +	private $_cache; +	private $_statePersister; +	private $_user; +	private $_globalization; +	private $_security; +	private $_assetManager; +	private $_authRules; +	private $_mode=TApplicationMode::Debug; +	private $_pageServiceID = self::PAGE_SERVICE_ID; +	public function __construct($basePath='protected',$cacheConfig=true) +	{ +				Prado::setApplication($this); +		$this->resolvePaths($basePath); +		if($cacheConfig) +			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE; +				$this->_uniqueID=md5($this->_runtimePath); +		$this->_parameters=new TMap; +		$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null)); +		Prado::setPathOfAlias('Application',$this->_basePath); +	} +	protected function resolvePaths($basePath) +	{ +				if(empty($basePath) || ($basePath=realpath($basePath))===false) +			throw new TConfigurationException('application_basepath_invalid',$basePath); +		if(is_file($basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE)) +			$configFile=$basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE; +		else if(is_file($basePath)) +		{ +			$configFile=$basePath; +			$basePath=dirname($configFile); +		} +		else +			$configFile=null; +				$runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH; +		if(is_writable($runtimePath)) +		{ +			if($configFile!==null) +			{ +				$runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion(); +				if(!is_dir($runtimePath)) +				{ +					if(@mkdir($runtimePath)===false) +						throw new TConfigurationException('application_runtimepath_failed',$runtimePath); +					@chmod($runtimePath, PRADO_CHMOD); 				} +				$this->setConfigurationFile($configFile); +			} +			$this->setBasePath($basePath); +			$this->setRuntimePath($runtimePath); +		} +		else +			throw new TConfigurationException('application_runtimepath_invalid',$runtimePath); +	} +	public function run() +	{ +		try +		{ +			$this->initApplication(); +			$n=count(self::$_steps); +			$this->_step=0; +			$this->_requestCompleted=false; +			while($this->_step<$n) +			{ +				if($this->_mode===self::STATE_OFF) +					throw new THttpException(503,'application_unavailable'); +				if($this->_requestCompleted) +					break; +				$method=self::$_steps[$this->_step]; +				$this->$method(); +				$this->_step++; +			} +		} +		catch(Exception $e) +		{ +			$this->onError($e); +		} +		$this->onEndRequest(); +	} +	public function completeRequest() +	{ +		$this->_requestCompleted=true; +	} +	public function getRequestCompleted() +	{ +		return $this->_requestCompleted; +	} +	public function getGlobalState($key,$defaultValue=null) +	{ +		return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue; +	} +	public function setGlobalState($key,$value,$defaultValue=null) +	{ +		$this->_stateChanged=true; +		if($value===$defaultValue) +			unset($this->_globals[$key]); +		else +			$this->_globals[$key]=$value; +	} +	public function clearGlobalState($key) +	{ +		$this->_stateChanged=true; +		unset($this->_globals[$key]); +	} +	protected function loadGlobals() +	{ +		$this->_globals=$this->getApplicationStatePersister()->load(); +	} +	protected function saveGlobals() +	{ +		if($this->_stateChanged) +		{ +			$this->_stateChanged=false; +			$this->getApplicationStatePersister()->save($this->_globals); +		} +	} +	public function getID() +	{ +		return $this->_id; +	} +	public function setID($value) +	{ +		$this->_id=$value; +	} +	public function getPageServiceID() +	{ +		return $this->_pageServiceID; +	} +	public function setPageServiceID($value) +	{ +		$this->_pageServiceID=$value; +	} +	public function getUniqueID() +	{ +		return $this->_uniqueID; +	} +	public function getMode() +	{ +		return $this->_mode; +	} +	public function setMode($value) +	{ +		$this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode'); +	} +	public function getBasePath() +	{ +		return $this->_basePath; +	} +	public function setBasePath($value) +	{ +		$this->_basePath=$value; +	} +	public function getConfigurationFile() +	{ +		return $this->_configFile; +	} +	public function setConfigurationFile($value) +	{ +		$this->_configFile=$value; +	} +	public function getRuntimePath() +	{ +		return $this->_runtimePath; +	} +	public function setRuntimePath($value) +	{ +		$this->_runtimePath=$value; +		if($this->_cacheFile) +			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE; +				$this->_uniqueID=md5($this->_runtimePath); +	} +	public function getService() +	{ +		return $this->_service; +	} +	public function setService($value) +	{ +		$this->_service=$value; +	} +	public function setModule($id,IModule $module) +	{ +		if(isset($this->_modules[$id])) +			throw new TConfigurationException('application_moduleid_duplicated',$id); +		else +			$this->_modules[$id]=$module; +	} +	public function getModule($id) +	{ +		return isset($this->_modules[$id])?$this->_modules[$id]:null; +	} +	public function getModules() +	{ +		return $this->_modules; +	} +	public function getParameters() +	{ +		return $this->_parameters; +	} +	public function getRequest() +	{ +		if(!$this->_request) +		{ +			$this->_request=new THttpRequest; +			$this->_request->init(null); +		} +		return $this->_request; +	} +	public function setRequest(THttpRequest $request) +	{ +		$this->_request=$request; +	} +	public function getResponse() +	{ +		if(!$this->_response) +		{ +			$this->_response=new THttpResponse; +			$this->_response->init(null); +		} +		return $this->_response; +	} +	public function setResponse(THttpResponse $response) +	{ +		$this->_response=$response; +	} +	public function getSession() +	{ +		if(!$this->_session) +		{ +			$this->_session=new THttpSession; +			$this->_session->init(null); +		} +		return $this->_session; +	} +	public function setSession(THttpSession $session) +	{ +		$this->_session=$session; +	} +	public function getErrorHandler() +	{ +		if(!$this->_errorHandler) +		{ +			$this->_errorHandler=new TErrorHandler; +			$this->_errorHandler->init(null); +		} +		return $this->_errorHandler; +	} +	public function setErrorHandler(TErrorHandler $handler) +	{ +		$this->_errorHandler=$handler; +	} +	public function getSecurityManager() +	{ +		if(!$this->_security) +		{ +			$this->_security=new TSecurityManager; +			$this->_security->init(null); +		} +		return $this->_security; +	} +	public function setSecurityManager(TSecurityManager $sm) +	{ +		$this->_security=$sm; +	} +	public function getAssetManager() +	{ +		if(!$this->_assetManager) +		{ +			$this->_assetManager=new TAssetManager; +			$this->_assetManager->init(null); +		} +		return $this->_assetManager; +	} +	public function setAssetManager(TAssetManager $value) +	{ +		$this->_assetManager=$value; +	} +	public function getApplicationStatePersister() +	{ +		if(!$this->_statePersister) +		{ +			$this->_statePersister=new TApplicationStatePersister; +			$this->_statePersister->init(null); +		} +		return $this->_statePersister; +	} +	public function setApplicationStatePersister(IStatePersister $persister) +	{ +		$this->_statePersister=$persister; +	} +	public function getCache() +	{ +		return $this->_cache; +	} +	public function setCache(ICache $cache) +	{ +		$this->_cache=$cache; +	} +	public function getUser() +	{ +		return $this->_user; +	} +	public function setUser(IUser $user) +	{ +		$this->_user=$user; +	} +	public function getGlobalization($createIfNotExists=true) +	{ +		if($this->_globalization===null && $createIfNotExists) +			$this->_globalization=new TGlobalization; +		return $this->_globalization; +	} +	public function setGlobalization(TGlobalization $glob) +	{ +		$this->_globalization=$glob; +	} +	public function getAuthorizationRules() +	{ +		if($this->_authRules===null) +			$this->_authRules=new TAuthorizationRuleCollection; +		return $this->_authRules; +	} +	public function applyConfiguration($config,$withinService=false) +	{ +		if($config->getIsEmpty()) +			return; +				foreach($config->getAliases() as $alias=>$path) +			Prado::setPathOfAlias($alias,$path); +		foreach($config->getUsings() as $using) +			Prado::using($using); +				if(!$withinService) +		{ +			foreach($config->getProperties() as $name=>$value) +				$this->setSubProperty($name,$value); +		} +		if(empty($this->_services)) +			$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null)); +				foreach($config->getParameters() as $id=>$parameter) +		{ +			if(is_array($parameter)) +			{ +				$component=Prado::createComponent($parameter[0]); +				foreach($parameter[1] as $name=>$value) +					$component->setSubProperty($name,$value); +				$this->_parameters->add($id,$component); +			} +			else +				$this->_parameters->add($id,$parameter); +		} +				$modules=array(); +		foreach($config->getModules() as $id=>$moduleConfig) +		{ +			list($moduleClass, $initProperties, $configElement)=$moduleConfig; +			$module=Prado::createComponent($moduleClass); +			if(!is_string($id)) +			{ +				$id='_module'.count($this->_modules); +				$initProperties['id']=$id; +			} +			$this->setModule($id,$module); +			foreach($initProperties as $name=>$value) +				$module->setSubProperty($name,$value); +			$modules[]=array($module,$configElement); +		} +		foreach($modules as $module) +			$module[0]->init($module[1]); +				foreach($config->getServices() as $serviceID=>$serviceConfig) +			$this->_services[$serviceID]=$serviceConfig; +				foreach($config->getExternalConfigurations() as $filePath=>$condition) +		{ +			if($condition!==true) +				$condition=$this->evaluateExpression($condition); +			if($condition) +			{ +				if(($path=Prado::getPathOfNamespace($filePath,self::CONFIG_FILE_EXT))===null || !is_file($path)) +					throw new TConfigurationException('application_includefile_invalid',$filePath); +				$c=new TApplicationConfiguration; +				$c->loadFromFile($path); +				$this->applyConfiguration($c,$withinService); +			} +		} +	} +	protected function initApplication() +	{ +		if($this->_configFile!==null) +		{ +			if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile)) +			{ +				$config=new TApplicationConfiguration; +				$config->loadFromFile($this->_configFile); +				if($this->_cacheFile!==null) +					file_put_contents($this->_cacheFile,Prado::serialize($config),LOCK_EX); +			} +			else +				$config=Prado::unserialize(file_get_contents($this->_cacheFile)); +			$this->applyConfiguration($config,false); +		} +		if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null) +			$serviceID=$this->getPageServiceID(); +		$this->startService($serviceID); +	} +	public function startService($serviceID) +	{ +		if(isset($this->_services[$serviceID])) +		{ +			list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID]; +			$service=Prado::createComponent($serviceClass); +			if(!($service instanceof IService)) +				throw new THttpException(500,'application_service_invalid',$serviceClass); +			if(!$service->getEnabled()) +				throw new THttpException(500,'application_service_unavailable',$serviceClass); +			$service->setID($serviceID); +			$this->setService($service); +			foreach($initProperties as $name=>$value) +				$service->setSubProperty($name,$value); +			if($configElement!==null) +			{ +				$config=new TApplicationConfiguration; +				$config->loadFromXml($configElement,$this->getBasePath()); +				$this->applyConfiguration($config,true); +			} +			$service->init($configElement); +		} +		else +			throw new THttpException(500,'application_service_unknown',$serviceID); +	} +	public function onError($param) +	{ +		Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication'); +		$this->raiseEvent('OnError',$this,$param); +		$this->getErrorHandler()->handleError($this,$param); +	} +	public function onBeginRequest() +	{ +		$this->raiseEvent('OnBeginRequest',$this,null); +	} +	public function onAuthentication() +	{ +		$this->raiseEvent('OnAuthentication',$this,null); +	} +	public function onAuthenticationComplete() +	{ +		$this->raiseEvent('OnAuthenticationComplete',$this,null); +	} +	public function onAuthorization() +	{ +		$this->raiseEvent('OnAuthorization',$this,null); +	} +	public function onAuthorizationComplete() +	{ +		$this->raiseEvent('OnAuthorizationComplete',$this,null); +	} +	public function onLoadState() +	{ +		$this->loadGlobals(); +		$this->raiseEvent('OnLoadState',$this,null); +	} +	public function onLoadStateComplete() +	{ +		$this->raiseEvent('OnLoadStateComplete',$this,null); +	} +	public function onPreRunService() +	{ +		$this->raiseEvent('OnPreRunService',$this,null); +	} +	public function runService() +	{ +		if($this->_service) +			$this->_service->run(); +	} +	public function onSaveState() +	{ +		$this->raiseEvent('OnSaveState',$this,null); +		$this->saveGlobals(); +	} +	public function onSaveStateComplete() +	{ +		$this->raiseEvent('OnSaveStateComplete',$this,null); +	} +	public function onPreFlushOutput() +	{ +		$this->raiseEvent('OnPreFlushOutput',$this,null); +	} +	public function flushOutput() +	{ +		$this->getResponse()->flush(); +	} +	public function onEndRequest() +	{ +		$this->saveGlobals();  		$this->raiseEvent('OnEndRequest',$this,null); +	} +} +class TApplicationMode extends TEnumerable +{ +	const Off='Off'; +	const Debug='Debug'; +	const Normal='Normal'; +	const Performance='Performance'; +} +class TApplicationConfiguration extends TComponent +{ +	private $_properties=array(); +	private $_usings=array(); +	private $_aliases=array(); +	private $_modules=array(); +	private $_services=array(); +	private $_parameters=array(); +	private $_includes=array(); +	private $_empty=true; +	public function loadFromFile($fname) +	{ +		$dom=new TXmlDocument; +		$dom->loadFromFile($fname); +		$this->loadFromXml($dom,dirname($fname)); +	} +	public function getIsEmpty() +	{ +		return $this->_empty; +	} +	public function loadFromXml($dom,$configPath) +	{ +				foreach($dom->getAttributes() as $name=>$value) +		{ +			$this->_properties[$name]=$value; +			$this->_empty=false; +		} +		foreach($dom->getElements() as $element) +		{ +			switch($element->getTagName()) +			{ +				case 'paths': +					$this->loadPathsXml($element,$configPath); +					break; +				case 'modules': +					$this->loadModulesXml($element,$configPath); +					break; +				case 'services': +					$this->loadServicesXml($element,$configPath); +					break; +				case 'parameters': +					$this->loadParametersXml($element,$configPath); +					break; +				case 'include': +					$this->loadExternalXml($element,$configPath); +					break; +				default: +										break; +			} +		} +	} +	protected function loadPathsXml($pathsNode,$configPath) +	{ +		foreach($pathsNode->getElements() as $element) +		{ +			switch($element->getTagName()) +			{ +				case 'alias': +				{ +					if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null) +					{ +						$path=str_replace('\\','/',$path); +						if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))								$p=realpath($path); +						else +							$p=realpath($configPath.DIRECTORY_SEPARATOR.$path); +						if($p===false || !is_dir($p)) +							throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path); +						if(isset($this->_aliases[$id])) +							throw new TConfigurationException('appconfig_alias_redefined',$id); +						$this->_aliases[$id]=$p; +					} +					else +						throw new TConfigurationException('appconfig_alias_invalid'); +					$this->_empty=false; +					break; +				} +				case 'using': +				{ +					if(($namespace=$element->getAttribute('namespace'))!==null) +						$this->_usings[]=$namespace; +					else +						throw new TConfigurationException('appconfig_using_invalid'); +					$this->_empty=false; +					break; +				} +				default: +					throw new TConfigurationException('appconfig_paths_invalid',$tagName); +			} +		} +	} +	protected function loadModulesXml($modulesNode,$configPath) +	{ +		foreach($modulesNode->getElements() as $element) +		{ +			if($element->getTagName()==='module') +			{ +				$properties=$element->getAttributes(); +				$id=$properties->itemAt('id'); +				$type=$properties->remove('class'); +				if($type===null) +					throw new TConfigurationException('appconfig_moduletype_required',$id); +				$element->setParent(null); +				if($id===null) +					$this->_modules[]=array($type,$properties->toArray(),$element); +				else +					$this->_modules[$id]=array($type,$properties->toArray(),$element); +				$this->_empty=false; +			} +			else +				throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName()); +		} +	} +	protected function loadServicesXml($servicesNode,$configPath) +	{ +		foreach($servicesNode->getElements() as $element) +		{ +			if($element->getTagName()==='service') +			{ +				$properties=$element->getAttributes(); +				if(($id=$properties->itemAt('id'))===null) +					throw new TConfigurationException('appconfig_serviceid_required'); +				if(($type=$properties->remove('class'))===null) +					throw new TConfigurationException('appconfig_servicetype_required',$id); +				$element->setParent(null); +				$this->_services[$id]=array($type,$properties->toArray(),$element); +				$this->_empty=false; +			} +			else +				throw new TConfigurationException('appconfig_services_invalid',$element->getTagName()); +		} +	} +	protected function loadParametersXml($parametersNode,$configPath) +	{ +		foreach($parametersNode->getElements() as $element) +		{ +			if($element->getTagName()==='parameter') +			{ +				$properties=$element->getAttributes(); +				if(($id=$properties->remove('id'))===null) +					throw new TConfigurationException('appconfig_parameterid_required'); +				if(($type=$properties->remove('class'))===null) +				{ +					if(($value=$properties->remove('value'))===null) +						$this->_parameters[$id]=$element; +					else +						$this->_parameters[$id]=$value; +				} +				else +					$this->_parameters[$id]=array($type,$properties->toArray()); +				$this->_empty=false; +			} +			else +				throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName()); +		} +	} +	protected function loadExternalXml($includeNode,$configPath) +	{ +		if(($when=$includeNode->getAttribute('when'))===null) +			$when=true; +		if(($filePath=$includeNode->getAttribute('file'))===null) +			throw new TConfigurationException('appconfig_includefile_required'); +		if(isset($this->_includes[$filePath])) +			$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')'; +		else +			$this->_includes[$filePath]=$when; +		$this->_empty=false; +	} +	public function getProperties() +	{ +		return $this->_properties; +	} +	public function getAliases() +	{ +		return $this->_aliases; +	} +	public function getUsings() +	{ +		return $this->_usings; +	} +	public function getModules() +	{ +		return $this->_modules; +	} +	public function getServices() +	{ +		return $this->_services; +	} +	public function getParameters() +	{ +		return $this->_parameters; +	} +	public function getExternalConfigurations() +	{ +		return $this->_includes; +	} +} +class TApplicationStatePersister extends TModule implements IStatePersister +{ +	const CACHE_NAME='prado:appstate'; +	public function init($config) +	{ +		$this->getApplication()->setApplicationStatePersister($this); +	} +	protected function getStateFilePath() +	{ +		return $this->getApplication()->getRuntimePath().'/global.cache'; +	} +	public function load() +	{ +		if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false) +			return unserialize($value); +		else +		{ +			if(($content=@file_get_contents($this->getStateFilePath()))!==false) +				return unserialize($content); +			else +				return null; +		} +	} +	public function save($state) +	{ +		$content=serialize($state); +		$saveFile=true; +		if(($cache=$this->getApplication()->getCache())!==null) +		{ +			if($cache->get(self::CACHE_NAME)===$content) +				$saveFile=false; +			else +				$cache->set(self::CACHE_NAME,$content); +		} +		if($saveFile) +		{ +			$fileName=$this->getStateFilePath(); +			file_put_contents($fileName,$content,LOCK_EX); +		} +	} +} +class TShellApplication extends TApplication +{ +	public function run() +	{ +		$this->initApplication(); +	} +} +?>
\ No newline at end of file @@ -92,6 +92,7 @@ PRADO component tags when you use it to edit PRADO templates.  <li><a href="mailto:haertl.mike@googlemail.com">Michael Härtl</a></li>  <li><a href="mailto:eirikhm@gmail.com">Eirik Hoem</a></li>  <li><a href="mailto:godzilla80@gmx.net">Yves Berkholz</a></li> +<li><a href="mailto:kamikazeole@gmail.com">Ole Helgesen</a></li>  </ul>  <h3>Translations</h3> diff --git a/tests/FunctionalTests/active-controls/protected/pages/ActiveDatePicker.page b/tests/FunctionalTests/active-controls/protected/pages/ActiveDatePicker.page index 64f37867..88117744 100755 --- a/tests/FunctionalTests/active-controls/protected/pages/ActiveDatePicker.page +++ b/tests/FunctionalTests/active-controls/protected/pages/ActiveDatePicker.page @@ -1,10 +1,10 @@  <html>  <com:THead/>  <body> -<com:TForm>
 +<com:TForm>  <h1>TActiveDatePicker test</h1> -<p>
 -<com:TActiveDatePicker ID="datepicker" DateFormat="MM-dd-yyyy" OnCallback="testDatePicker"/>
 +<p> +<com:TActiveDatePicker ID="datepicker" DateFormat="MM-dd-yyyy" OnCallback="testDatePicker"/>  <com:TActiveLabel ID="status" /><br/>  <com:TActiveButton ID="decreaseButton" OnClick="decrease" Text="-1" OnCallback="testDatePicker"/>  <com:TActiveButton ID="todayButton" OnClick="today" Text="Today" OnCallback="testDatePicker"/> @@ -18,8 +18,11 @@ ShowCalendar=false  <com:TActiveDatePicker ID="datepicker2" DateFormat="MM-dd-yyyy" OnCallback="testDatePicker2" InputMode="DropDownList" ShowCalendar="false"/>  <com:TActiveLabel ID="status2" /><br/>  </p> +<p>Partial Calendar</p> +<p> +<com:TActiveDatePicker ID="datepicker3" DateFormat="MMMM/yyyy" OnCallback="testDatePicker3" InputMode="DropDownList" ShowCalendar="true"/> +<com:TActiveLabel ID="status3" /><br/> -
  </com:TForm>  </body>  </html>
\ No newline at end of file diff --git a/tests/FunctionalTests/active-controls/protected/pages/ActiveDatePicker.php b/tests/FunctionalTests/active-controls/protected/pages/ActiveDatePicker.php index 4897a146..300574aa 100755 --- a/tests/FunctionalTests/active-controls/protected/pages/ActiveDatePicker.php +++ b/tests/FunctionalTests/active-controls/protected/pages/ActiveDatePicker.php @@ -17,7 +17,11 @@ class ActiveDatePicker extends TPage  {  	public function testDatePicker2($sender, $param){  		$this->status2->Text = $this->datepicker2->getText();  	} -	 + +	public function testDatePicker3($sender, $param){ +		$this->status3->Text = $this->datepicker3->getText(); +	} +  	public function today ($sender, $param)  	{  		$this->datepicker->setTimestamp(time()); diff --git a/tests/FunctionalTests/active-controls/tests/ActiveDatePickerTestCase.php b/tests/FunctionalTests/active-controls/tests/ActiveDatePickerTestCase.php index 5faee611..c3b47934 100755 --- a/tests/FunctionalTests/active-controls/tests/ActiveDatePickerTestCase.php +++ b/tests/FunctionalTests/active-controls/tests/ActiveDatePickerTestCase.php @@ -104,6 +104,16 @@ class ActiveDatePickerTestCase extends SeleniumTestCase  		$this->pause(800);  		$dateToCheck=mktime(0,0,0,(int)date('m'),(int)date('d'), 2005);  		$this->verifyText("status2", date('m-d-Y', $dateToCheck)); + + +		$this->verifyText("status3", ""); +		$dateToCheck=time(); +		$this->verifySelected("datepicker3_month", date('F', $dateToCheck)); +		$this->verifySelected("datepicker3_year", date('Y', $dateToCheck)); +		$this->select("datepicker3_year", 2005); +		$this->pause(800); +		$dateToCheck=mktime(0,0,0,(int)date('m'),(int)date('d'), 2005); +		$this->verifyText("status3", date('m/Y', $dateToCheck));  	}  } diff --git a/tests/FunctionalTests/tickets/protected/pages/Issue216.page b/tests/FunctionalTests/tickets/protected/pages/Issue216.page new file mode 100644 index 00000000..2efff728 --- /dev/null +++ b/tests/FunctionalTests/tickets/protected/pages/Issue216.page @@ -0,0 +1,15 @@ +<com:TContent ID="Content">
 +	<h1>TTabPanel doesn't preserve active tab on callback request</h1>
 +
 +	<com:TTabPanel id="tabpanel">
 +		<com:TTabView id="tab1" Caption="Tab 1">
 +			<p>This is Tab 1</p>
 +		</com:TTabView>
 +		<com:TTabView id="tab2" Caption="Tab 2">
 +			<p>This is Tab 2</p>
 +		</com:TTabView>
 +	</com:TTabPanel>
 +	
 +	<com:TActiveButton id="btn1" OnCallback="buttonClickCallback" Text ="Click me"/>
 +	<com:TActiveLabel id="result"/>
 +</com:TContent>
\ No newline at end of file diff --git a/tests/FunctionalTests/tickets/protected/pages/Issue216.php b/tests/FunctionalTests/tickets/protected/pages/Issue216.php new file mode 100644 index 00000000..15491e2e --- /dev/null +++ b/tests/FunctionalTests/tickets/protected/pages/Issue216.php @@ -0,0 +1,14 @@ +<?php
 +Prado::using('System.Web.UI.ActiveControls.*');
 +
 +class Issue216 extends TPage
 +{
 +	public function buttonClickCallback($sender, $param)
 +	{
 +		
 +		$this->result->setText('Tab ActiveIndex is : '.$this->tabpanel->ActiveViewIndex);
 +		
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/tests/FunctionalTests/tickets/tests/Issue216TestCase.php b/tests/FunctionalTests/tickets/tests/Issue216TestCase.php new file mode 100644 index 00000000..1cfdf0cd --- /dev/null +++ b/tests/FunctionalTests/tickets/tests/Issue216TestCase.php @@ -0,0 +1,28 @@ +<?php
 +
 +class Issue216TestCase extends SeleniumTestCase
 +{
 +	function test()
 +	{
 +		$this->open('tickets/index.php?page=Issue216');
 +		$this->assertTextPresent('TTabPanel doesn\'t preserve active tab on callback request');
 +		
 +		$this->assertVisible('ctl0_Content_tab1');
 +
 +		$this->click("ctl0_Content_btn1");
 +		$this->pause(800);
 +
 +		$this->assertText("ctl0_Content_result", "Tab ActiveIndex is : 0");
 +
 +		$this->click("ctl0_Content_tab2_0");
 +		$this->pause(800);
 +
 +		$this->assertVisible('ctl0_Content_tab2');
 +
 +		$this->click("ctl0_Content_btn1");
 +		$this->pause(800);
 +		$this->assertText("ctl0_Content_result", "Tab ActiveIndex is : 1");
 +	}
 +}
 +
 +?>
\ No newline at end of file  | 
