summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
authorctrlaltca@gmail.com <>2011-05-21 17:10:29 +0000
committerctrlaltca@gmail.com <>2011-05-21 17:10:29 +0000
commit6f00b28a1d9c7409c956a83866eac48a9493e83c (patch)
treefb3e14f0a527cf32d186932b13bd6ae9ed50a5c1 /framework
parent5a91b2a3328c8c15ce9dbed9a599ab87f9e8f112 (diff)
branch/3.1: merged bugfixesfrom trunk/ up to r2880; correct svn:mergeinfo property
Diffstat (limited to 'framework')
-rw-r--r--framework/Collections/TListItemCollection.php164
-rw-r--r--framework/Collections/TQueue.php8
-rw-r--r--framework/I18N/Translation.php201
-rw-r--r--framework/PradoBase.php27
-rw-r--r--framework/Security/TSecurityManager.php547
-rw-r--r--framework/Util/TSimpleDateFormatter.php3
-rw-r--r--framework/Web/Javascripts/source/prado/activecontrols/activecontrols3.js1
-rw-r--r--framework/Web/TUrlMapping.php282
-rw-r--r--framework/Web/UI/ActiveControls/TCallbackClientScript.php3
-rw-r--r--framework/Web/UI/TTemplateManager.php12
-rw-r--r--framework/Web/UI/WebControls/TBoundColumn.php16
-rw-r--r--framework/Web/UI/WebControls/TDatePicker.php4
-rw-r--r--framework/Web/UI/WebControls/TListControl.php151
13 files changed, 724 insertions, 695 deletions
diff --git a/framework/Collections/TListItemCollection.php b/framework/Collections/TListItemCollection.php
new file mode 100644
index 00000000..d9adb161
--- /dev/null
+++ b/framework/Collections/TListItemCollection.php
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * TListItemCollection class file
+ *
+ * @author Robin J. Rogge <rojaro@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2010 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TListControl.php 2624 2009-03-19 21:20:47Z godzilla80@gmx.net $
+ * @package System.Collections
+ */
+
+/**
+ * Includes the supporting classes
+ */
+Prado::using('System.Collections.TList');
+Prado::using('System.Web.UI.WebControls.TListItem');
+
+/**
+ * TListItemCollection class.
+ *
+ * TListItemCollection maintains a list of {@link TListItem} for {@link TListControl}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: TListControl.php 2624 2009-03-19 21:20:47Z godzilla80@gmx.net $
+ * @package System.Collections
+ * @since 3.0
+ */
+class TListItemCollection extends TList
+{
+ /**
+ * Creates a list item object.
+ * This method may be overriden to provide a customized list item object.
+ * @param integer index where the newly created item is to be inserted at.
+ * If -1, the item will be appended to the end.
+ * @return TListItem list item object
+ */
+ public function createListItem($index=-1)
+ {
+ $item=$this->createNewListItem();
+ if($index<0)
+ $this->add($item);
+ else
+ $this->insertAt($index,$item);
+ return $item;
+ }
+
+ /**
+ * @return TListItem new item.
+ */
+ protected function createNewListItem($text=null)
+ {
+ $item = new TListItem;
+ if($text!==null)
+ $item->setText($text);
+ return $item;
+ }
+
+ /**
+ * Inserts an item into the collection.
+ * @param integer the location where the item will be inserted.
+ * The current item at the place and the following ones will be moved backward.
+ * @param TListItem the item to be inserted.
+ * @throws TInvalidDataTypeException if the item being inserted is neither a string nor TListItem
+ */
+ public function insertAt($index,$item)
+ {
+ if(is_string($item))
+ $item = $this->createNewListItem($item);
+ if(!($item instanceof TListItem))
+ throw new TInvalidDataTypeException('listitemcollection_item_invalid',get_class($this));
+ parent::insertAt($index,$item);
+ }
+
+ /**
+ * Finds the lowest cardinal index of the item whose value is the one being looked for.
+ * @param string the value to be looked for
+ * @param boolean whether to look for disabled items also
+ * @return integer the index of the item found, -1 if not found.
+ */
+ public function findIndexByValue($value,$includeDisabled=true)
+ {
+ $value=TPropertyValue::ensureString($value);
+ $index=0;
+ foreach($this as $item)
+ {
+ if($item->getValue()===$value && ($includeDisabled || $item->getEnabled()))
+ return $index;
+ $index++;
+ }
+ return -1;
+ }
+
+ /**
+ * Finds the lowest cardinal index of the item whose text is the one being looked for.
+ * @param string the text to be looked for
+ * @param boolean whether to look for disabled items also
+ * @return integer the index of the item found, -1 if not found.
+ */
+ public function findIndexByText($text,$includeDisabled=true)
+ {
+ $text=TPropertyValue::ensureString($text);
+ $index=0;
+ foreach($this as $item)
+ {
+ if($item->getText()===$text && ($includeDisabled || $item->getEnabled()))
+ return $index;
+ $index++;
+ }
+ return -1;
+ }
+
+ /**
+ * Finds the item whose value is the one being looked for.
+ * @param string the value to be looked for
+ * @param boolean whether to look for disabled items also
+ * @return TListItem the item found, null if not found.
+ */
+ public function findItemByValue($value,$includeDisabled=true)
+ {
+ if(($index=$this->findIndexByValue($value,$includeDisabled))>=0)
+ return $this->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * Finds the item whose text is the one being looked for.
+ * @param string the text to be looked for
+ * @param boolean whether to look for disabled items also
+ * @return TListItem the item found, null if not found.
+ */
+ public function findItemByText($text,$includeDisabled=true)
+ {
+ if(($index=$this->findIndexByText($text,$includeDisabled))>=0)
+ return $this->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * Loads state into every item in the collection.
+ * This method should only be used by framework and control developers.
+ * @param array|null state to be loaded.
+ */
+ public function loadState($state)
+ {
+ $this->clear();
+ if($state!==null)
+ $this->copyFrom($state);
+ }
+
+ /**
+ * Saves state of items.
+ * This method should only be used by framework and control developers.
+ * @return array|null the saved state
+ */
+ public function saveState()
+ {
+ return ($this->getCount()>0) ? $this->toArray() : null;
+ }
+}
diff --git a/framework/Collections/TQueue.php b/framework/Collections/TQueue.php
index 1eacfb0a..581a7109 100644
--- a/framework/Collections/TQueue.php
+++ b/framework/Collections/TQueue.php
@@ -4,7 +4,7 @@
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2008 PradoSoft
+ * @copyright Copyright &copy; 2005-2008 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Collections
@@ -105,8 +105,8 @@ class TQueue extends TComponent implements IteratorAggregate,Countable
}
/**
- * Returns the item at the top of the queue.
- * Unlike {@link pop()}, this method does not remove the item from the queue.
+ * Returns the first item at the front of the queue.
+ * Unlike {@link dequeue()}, this method does not remove the item from the queue.
* @return mixed item at the top of the queue
* @throws TInvalidOperationException if the queue is empty
*/
@@ -115,7 +115,7 @@ class TQueue extends TComponent implements IteratorAggregate,Countable
if($this->_c===0)
throw new TInvalidOperationException('queue_empty');
else
- return $this->_d[$this->_c-1];
+ return $this->_d[0];
}
/**
diff --git a/framework/I18N/Translation.php b/framework/I18N/Translation.php
index a0fa504d..8df36bc6 100644
--- a/framework/I18N/Translation.php
+++ b/framework/I18N/Translation.php
@@ -1,108 +1,107 @@
-<?php
-/**
- * Translation, static.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * Translation, static.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2008 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.I18N
- */
-
- /**
- * Get the MessageFormat class.
- */
-Prado::using('System.I18N.core.MessageFormat');
-
-
-/**
- * Translation class.
- *
- * Provides translation using a static MessageFormatter.
- *
- * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version v1.0, last update on Tue Dec 28 11:54:48 EST 2004
- * @package System.I18N
- */
-class Translation extends TComponent
-{
- /**
- * The array of formatters. We define 1 formatter per translation catalog
- * This is a class static variable.
- * @var array
- */
- protected static $formatters=array();
-
- /**
- * Initialize the TTranslate translation components
- */
- public static function init($catalogue='messages')
- {
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.I18N
+ */
+
+/**
+ * Get the MessageFormat class.
+ */
+Prado::using('System.I18N.core.MessageFormat');
+
+
+/**
+ * Translation class.
+ *
+ * Provides translation using a static MessageFormatter.
+ *
+ * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version v1.0, last update on Tue Dec 28 11:54:48 EST 2004
+ * @package System.I18N
+ */
+class Translation extends TComponent
+{
+ /**
+ * The array of formatters. We define 1 formatter per translation catalog
+ * This is a class static variable.
+ * @var array
+ */
+ protected static $formatters=array();
+
+ /**
+ * Initialize the TTranslate translation components
+ */
+ public static function init($catalogue='messages')
+ {
static $saveEventHandlerAttached=false;
- //initialized the default class wide formatter
- if(!isset(self::$formatters[$catalogue]))
- {
- $app = Prado::getApplication()->getGlobalization();
- $config = $app->getTranslationConfiguration();
- $source = MessageSource::factory($config['type'],
- $config['source'],
- $config['filename']);
-
- $source->setCulture($app->getCulture());
-
- if($config['cache'])
- $source->setCache(new MessageCache($config['cache']));
-
- self::$formatters[$catalogue] = new MessageFormat($source, $app->getCharset());
-
- //mark untranslated text
- if($ps=$config['marker'])
- self::$formatters[$catalogue]->setUntranslatedPS(array($ps,$ps));
-
+ //initialized the default class wide formatter
+ if(!isset(self::$formatters[$catalogue]))
+ {
+ $app = Prado::getApplication()->getGlobalization();
+ $config = $app->getTranslationConfiguration();
+ $source = MessageSource::factory($config['type'],
+ $config['source'],
+ $config['filename']);
+
+ $source->setCulture($app->getCulture());
+
+ if(TPropertyValue::ensureBoolean($config['cache']))
+ $source->setCache(new MessageCache($config['cache']));
+
+ self::$formatters[$catalogue] = new MessageFormat($source, $app->getCharset());
+
+ //mark untranslated text
+ if($ps=$config['marker'])
+ self::$formatters[$catalogue]->setUntranslatedPS(array($ps,$ps));
+
//save the message on end request
- // Do it only once !
- if (!$saveEventHandlerAttached)
+ // Do it only once !
+ if(!$saveEventHandlerAttached && TPropertyValue::ensureBoolean($config['autosave']))
{
- Prado::getApplication()->attachEventHandler(
+ Prado::getApplication()->attachEventHandler(
'OnEndRequest', array('Translation', 'saveMessages'));
$saveEventHandlerAttached=true;
- }
- }
- }
-
- /**
- * Get the static formatter from this component.
- * @return MessageFormat formattter.
- * @see localize()
- */
- public static function formatter($catalogue='messages')
- {
- return self::$formatters[$catalogue];
- }
-
- /**
- * Save untranslated messages to the catalogue.
- */
- public static function saveMessages()
- {
- static $onceonly = true;
-
- if($onceonly)
- {
- foreach (self::$formatters as $catalogue=>$formatter)
- {
- $app = Prado::getApplication()->getGlobalization();
- $config = $app->getTranslationConfiguration();
- if(isset($config['autosave']))
- {
- $formatter->getSource()->setCulture($app->getCulture());
- $formatter->getSource()->save($catalogue);
- }
- }
- $onceonly = false;
- }
- }
-}
-
+ }
+ }
+ }
+
+ /**
+ * Get the static formatter from this component.
+ * @return MessageFormat formattter.
+ * @see localize()
+ */
+ public static function formatter($catalogue='messages')
+ {
+ return self::$formatters[$catalogue];
+ }
+
+ /**
+ * Save untranslated messages to the catalogue.
+ */
+ public static function saveMessages()
+ {
+ static $onceonly = true;
+
+ if($onceonly)
+ {
+ foreach (self::$formatters as $catalogue=>$formatter)
+ {
+ $app = Prado::getApplication()->getGlobalization();
+ $config = $app->getTranslationConfiguration();
+ if(isset($config['autosave']))
+ {
+ $formatter->getSource()->setCulture($app->getCulture());
+ $formatter->getSource()->save($catalogue);
+ }
+ }
+ $onceonly = false;
+ }
+ }
+}
diff --git a/framework/PradoBase.php b/framework/PradoBase.php
index 3a982ec5..222f492e 100644
--- a/framework/PradoBase.php
+++ b/framework/PradoBase.php
@@ -341,21 +341,24 @@ class PradoBase
* @param string extension to be appended if the namespace refers to a file
* @return string file path corresponding to the namespace, null if namespace is invalid
*/
- public static function getPathOfNamespace($namespace,$ext='')
+ 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
+ if(self::CLASS_FILE_EXT === $ext || empty($ext))
{
- $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;
+ if(isset(self::$_usings[$namespace]))
+ return self::$_usings[$namespace];
+
+ if(isset(self::$_aliases[$namespace]))
+ return self::$_aliases[$namespace];
}
+
+ $segs = explode('.',$namespace);
+ $alias = array_shift($segs);
+
+ if(null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias)))
+ return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file === '*') ? '' : DIRECTORY_SEPARATOR.$file.$ext);
+
+ return null;
}
/**
diff --git a/framework/Security/TSecurityManager.php b/framework/Security/TSecurityManager.php
index d43c9fec..18ced3c7 100644
--- a/framework/Security/TSecurityManager.php
+++ b/framework/Security/TSecurityManager.php
@@ -1,281 +1,268 @@
-<?php
-/**
- * TSecurityManager class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+
+/**
+ * TSecurityManager class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2008 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Security
- */
-
-/**
- * TSecurityManager class
- *
- * TSecurityManager provides private keys, hashing and encryption
- * functionalities that may be used by other PRADO components,
- * such as viewstate persister, cookies.
- *
- * TSecurityManager is mainly used to protect data from being tampered
- * and viewed. It can generate HMAC and encrypt the data.
- * The private key used to generate HMAC is set by {@link setValidationKey ValidationKey}.
- * The key used to encrypt data is specified by {@link setEncryptionKey EncryptionKey}.
- * If the above keys are not explicitly set, random keys will be generated
- * and used.
- *
- * To prefix data with an HMAC, call {@link hashData()}.
- * To validate if data is tampered, call {@link validateData()}, which will
- * return the real data if it is not tampered.
- * The algorithm used to generated HMAC is specified by {@link setValidation Validation}.
- *
- * To encrypt and decrypt data, call {@link encrypt()} and {@link decrypt()}
- * respectively. The encryption algorithm can be set by {@link setEncryption Encryption}.
- *
- * Note, to use encryption, the PHP Mcrypt extension must be loaded.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Security
- * @since 3.0
- */
-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';
-
- /**
- * Initializes the module.
- * The security module is registered with the application.
- * @param TXmlElement initial module configuration
- */
- public function init($config)
- {
- $this->getApplication()->setSecurityManager($this);
- }
-
- /**
- * Generates a random key.
- */
- protected function generateRandomKey()
- {
- return rand().rand().rand().rand();
- }
-
- /**
- * @return string the private key used to generate HMAC.
- * If the key is not explicitly set, a random one is generated and returned.
- */
- 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;
- }
-
- /**
- * @param string the key used to generate HMAC
- * @throws TInvalidDataValueException if the key is empty
- */
- public function setValidationKey($value)
- {
- if($value!=='')
- $this->_validationKey=$value;
- else
- throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
- }
-
- /**
- * @return string the private key used to encrypt/decrypt data.
- * If the key is not explicitly set, a random one is generated and returned.
- */
- 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;
- }
-
- /**
- * @param string the key used to encrypt/decrypt data.
- * @throws TInvalidDataValueException if the key is empty
- */
- public function setEncryptionKey($value)
- {
- if($value!=='')
- $this->_encryptionKey=$value;
- else
- throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
- }
-
- /**
- * @return TSecurityManagerValidationMode hashing algorithm used to generate HMAC. Defaults to TSecurityManagerValidationMode::SHA1.
- */
- public function getValidation()
- {
- return $this->_validation;
- }
-
- /**
- * @param TSecurityManagerValidationMode hashing algorithm used to generate HMAC.
- */
- public function setValidation($value)
- {
- $this->_validation=TPropertyValue::ensureEnum($value,'TSecurityManagerValidationMode');
- }
-
- /**
- * @return string the algorithm used to encrypt/decrypt data. Defaults to '3DES'.
- */
- public function getEncryption()
- {
- return $this->_encryption;
- }
-
- /**
- * @throws TNotSupportedException Do not call this method presently.
- */
- public function setEncryption($value)
- {
- throw new TNotSupportedException('Currently only 3DES encryption is supported');
- }
-
- /**
- * Encrypts data with {@link getEncryptionKey EncryptionKey}.
- * @param string data to be encrypted.
- * @return string the encrypted data
- * @throws TNotSupportedException if PHP Mcrypt extension is not loaded
- */
- 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');
- }
-
- /**
- * Decrypts data with {@link getEncryptionKey EncryptionKey}.
- * @param string data to be decrypted.
- * @return string the decrypted data
- * @throws TNotSupportedException if PHP Mcrypt extension is not loaded
- */
- 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');
- }
-
- /**
- * Prefixes data with an HMAC.
- * @param string data to be hashed.
- * @return string data prefixed with HMAC
- */
- public function hashData($data)
- {
- $hmac=$this->computeHMAC($data);
- return $hmac.$data;
- }
-
- /**
- * Validates if data is tampered.
- * @param string data to be validated. The data must be previously
- * generated using {@link hashData()}.
- * @return string the real data with HMAC stripped off. False if the data
- * is tampered.
- */
- 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;
- }
-
- /**
- * Computes the HMAC for the data with {@link getValidationKey ValidationKey}.
- * @param string data to be generated HMAC
- * @return string the HMAC for the data
- */
- 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)));
- }
-}
-
-
-/**
- * TSecurityManagerValidationMode class.
- * TSecurityManagerValidationMode defines the enumerable type for the possible validation modes
- * that can be used by {@link TSecurityManager}.
- *
- * The following enumerable values are defined:
- * - MD5: an MD5 hash is generated from the data and used for validation.
- * - SHA1: an SHA1 hash is generated from the data and used for validation.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Security
- * @since 3.0.4
- */
-class TSecurityManagerValidationMode extends TEnumerable
-{
- const MD5='MD5';
- const SHA1='SHA1';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Security
+ */
+
+/**
+ * TSecurityManager class
+ *
+ * TSecurityManager provides private keys, hashing and encryption
+ * functionalities that may be used by other PRADO components,
+ * such as viewstate persister, cookies.
+ *
+ * TSecurityManager is mainly used to protect data from being tampered
+ * and viewed. It can generate HMAC and encrypt the data.
+ * The private key used to generate HMAC is set by {@link setValidationKey ValidationKey}.
+ * The key used to encrypt data is specified by {@link setEncryptionKey EncryptionKey}.
+ * If the above keys are not explicitly set, random keys will be generated
+ * and used.
+ *
+ * To prefix data with an HMAC, call {@link hashData()}.
+ * To validate if data is tampered, call {@link validateData()}, which will
+ * return the real data if it is not tampered.
+ * The algorithm used to generated HMAC is specified by {@link setValidation Validation}.
+ *
+ * To encrypt and decrypt data, call {@link encrypt()} and {@link decrypt()}
+ * respectively. The encryption algorithm can be set by {@link setEncryption Encryption}.
+ *
+ * Note, to use encryption, the PHP Mcrypt extension must be loaded.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Security
+ * @since 3.0
+ */
+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';
+
+ /**
+ * Initializes the module.
+ * The security module is registered with the application.
+ * @param TXmlElement initial module configuration
+ */
+ public function init($config)
+ {
+ $this->getApplication()->setSecurityManager($this);
+ }
+
+ /**
+ * Generates a random key.
+ */
+ protected function generateRandomKey()
+ {
+ return rand().rand().rand().rand();
+ }
+
+ /**
+ * @return string the private key used to generate HMAC.
+ * If the key is not explicitly set, a random one is generated and returned.
+ */
+ public function getValidationKey()
+ {
+ if(null === $this->_validationKey) {
+ if(null === ($this->_validationKey = $this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))) {
+ $this->_validationKey = $this->generateRandomKey();
+ $this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY, $this->_validationKey, null);
+ }
+ }
+ return $this->_validationKey;
+ }
+
+ /**
+ * @param string the key used to generate HMAC
+ * @throws TInvalidDataValueException if the key is empty
+ */
+ public function setValidationKey($value)
+ {
+ if('' === $value)
+ throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
+
+ $this->_validationKey = $value;
+ }
+
+ /**
+ * @return string the private key used to encrypt/decrypt data.
+ * If the key is not explicitly set, a random one is generated and returned.
+ */
+ public function getEncryptionKey()
+ {
+ if(null === $this->_encryptionKey) {
+ if(null === ($this->_encryptionKey = $this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))) {
+ $this->_encryptionKey = $this->generateRandomKey();
+ $this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY, $this->_encryptionKey, null);
+ }
+ }
+ return $this->_encryptionKey;
+ }
+
+ /**
+ * @param string the key used to encrypt/decrypt data.
+ * @throws TInvalidDataValueException if the key is empty
+ */
+ public function setEncryptionKey($value)
+ {
+ if('' === $value)
+ throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
+
+ $this->_encryptionKey = $value;
+ }
+
+ /**
+ * @return TSecurityManagerValidationMode hashing algorithm used to generate HMAC. Defaults to TSecurityManagerValidationMode::SHA1.
+ */
+ public function getValidation()
+ {
+ return $this->_validation;
+ }
+
+ /**
+ * @param TSecurityManagerValidationMode hashing algorithm used to generate HMAC.
+ */
+ public function setValidation($value)
+ {
+ $this->_validation = TPropertyValue::ensureEnum($value, 'TSecurityManagerValidationMode');
+ }
+
+ /**
+ * @return string the algorithm used to encrypt/decrypt data. Defaults to '3DES'.
+ */
+ public function getEncryption()
+ {
+ return $this->_encryption;
+ }
+
+ /**
+ * @throws TNotSupportedException Do not call this method presently.
+ */
+ public function setEncryption($value)
+ {
+ throw new TNotSupportedException('Currently only 3DES encryption is supported');
+ }
+
+ /**
+ * Encrypts data with {@link getEncryptionKey EncryptionKey}.
+ * @param string data to be encrypted.
+ * @return string the encrypted data
+ * @throws TNotSupportedException if PHP Mcrypt extension is not loaded
+ */
+ public function encrypt($data)
+ {
+ if(!function_exists('mcrypt_encrypt'))
+ throw new TNotSupportedException('securitymanager_mcryptextension_required');
+
+ $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;
+ }
+
+ /**
+ * Decrypts data with {@link getEncryptionKey EncryptionKey}.
+ * @param string data to be decrypted.
+ * @return string the decrypted data
+ * @throws TNotSupportedException if PHP Mcrypt extension is not loaded
+ */
+ public function decrypt($data)
+ {
+ if(!function_exists('mcrypt_decrypt'))
+ throw new TNotSupportedException('securitymanager_mcryptextension_required');
+
+ $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 $decrypted;
+ }
+
+ /**
+ * Prefixes data with an HMAC.
+ * @param string data to be hashed.
+ * @return string data prefixed with HMAC
+ */
+ public function hashData($data)
+ {
+ $hmac = $this->computeHMAC($data);
+ return $hmac.$data;
+ }
+
+ /**
+ * Validates if data is tampered.
+ * @param string data to be validated. The data must be previously
+ * generated using {@link hashData()}.
+ * @return string the real data with HMAC stripped off. False if the data
+ * is tampered.
+ */
+ public function validateData($data)
+ {
+ $len = 'SHA1' === $this->_validation ? 40 : 32;
+ if(strlen($data) < $len)
+ return false;
+
+ $hmac = substr($data, 0, $len);
+ $data2 = substr($data, $len);
+ return $hmac === $this->computeHMAC($data2) ? $data2 : false;
+ }
+
+ /**
+ * Computes the HMAC for the data with {@link getValidationKey ValidationKey}.
+ * @param string data to be generated HMAC
+ * @return string the HMAC for the data
+ */
+ protected function computeHMAC($data)
+ {
+ if('SHA1' === $this->_validation) {
+ $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)));
+ }
+}
+
+/**
+ * TSecurityManagerValidationMode class.
+ * TSecurityManagerValidationMode defines the enumerable type for the possible validation modes
+ * that can be used by {@link TSecurityManager}.
+ *
+ * The following enumerable values are defined:
+ * - MD5: an MD5 hash is generated from the data and used for validation.
+ * - SHA1: an SHA1 hash is generated from the data and used for validation.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Security
+ * @since 3.0.4
+ */
+class TSecurityManagerValidationMode extends TEnumerable
+{
+ const MD5 = 'MD5';
+ const SHA1 = 'SHA1';
+}
diff --git a/framework/Util/TSimpleDateFormatter.php b/framework/Util/TSimpleDateFormatter.php
index 07a59398..15842f27 100644
--- a/framework/Util/TSimpleDateFormatter.php
+++ b/framework/Util/TSimpleDateFormatter.php
@@ -301,7 +301,8 @@ class TSimpleDateFormatter
}
}
if ($i_val != $this->length($value))
- throw new TInvalidDataValueException("Pattern '{$this->pattern}' mismatch", $value);
+ return null;
+ //throw new TInvalidDataValueException("Pattern '{$this->pattern}' mismatch", $value);
if(!$defaultToCurrentTime && ($month === null || $day === null || $year === null))
return null;
else
diff --git a/framework/Web/Javascripts/source/prado/activecontrols/activecontrols3.js b/framework/Web/Javascripts/source/prado/activecontrols/activecontrols3.js
index 56395d44..97bd4e07 100644
--- a/framework/Web/Javascripts/source/prado/activecontrols/activecontrols3.js
+++ b/framework/Web/Javascripts/source/prado/activecontrols/activecontrols3.js
@@ -188,7 +188,6 @@ Prado.WebUI.TTimeTriggeredCallback = Base.extend(
startTimer : function()
{
- setTimeout(this.onTimerEvent.bind(this), 100);
if(typeof(this.timer) == 'undefined' || this.timer == null)
this.timer = setInterval(this.onTimerEvent.bind(this),this.options.Interval*1000);
},
diff --git a/framework/Web/TUrlMapping.php b/framework/Web/TUrlMapping.php
index 47232401..b95779fe 100644
--- a/framework/Web/TUrlMapping.php
+++ b/framework/Web/TUrlMapping.php
@@ -4,7 +4,7 @@
*
* @author Wei Zhuo <weizhuo[at]gamil[dot]com>
* @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2008 PradoSoft
+ * @copyright Copyright &copy; 2005-2008 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Web
@@ -264,7 +264,7 @@ class TUrlMapping extends TUrlManager
if(is_string($key))
$params[$key]=$value;
}
- if (!$pattern->getIsWildCardPattern())
+ if (!$pattern->getIsWildCardPattern())
$params[$pattern->getServiceID()]=$pattern->getServiceParameter();
return $params;
}
@@ -300,8 +300,8 @@ class TUrlMapping extends TUrlManager
if(!(is_array($getItems) || ($getItems instanceof Traversable)))
$getItems=array();
$key=$serviceID.':'.$serviceParam;
- $wildCardKey = ($pos=strrpos($serviceParam,'.'))!==false ?
- $serviceID.':'.substr($serviceParam,0,$pos).'.*' : $serviceID.':*';
+ $wildCardKey = ($pos=strrpos($serviceParam,'.'))!==false ?
+ $serviceID.':'.substr($serviceParam,0,$pos).'.*' : $serviceID.':*';
if(isset($this->_constructRules[$key]))
{
foreach($this->_constructRules[$key] as $rule)
@@ -309,16 +309,16 @@ class TUrlMapping extends TUrlManager
if($rule->supportCustomUrl($getItems))
return $rule->constructUrl($getItems,$encodeAmpersand,$encodeGetItems);
}
- }
- elseif(isset($this->_constructRules[$wildCardKey]))
- {
+ }
+ elseif(isset($this->_constructRules[$wildCardKey]))
+ {
foreach($this->_constructRules[$wildCardKey] as $rule)
{
if($rule->supportCustomUrl($getItems))
- {
- $getItems['*']= $pos ? substr($serviceParam,$pos+1) : $serviceParam;
+ {
+ $getItems['*']= $pos ? substr($serviceParam,$pos+1) : $serviceParam;
return $rule->constructUrl($getItems,$encodeAmpersand,$encodeGetItems);
- }
+ }
}
}
}
@@ -380,42 +380,42 @@ class TUrlMapping extends TUrlManager
* The {@link setServiceParameter ServiceParameter} and {@link setServiceID ServiceID}
* (the default ID is 'page') set the service parameter and service id respectively.
*
- * Since 3.1.4 you can also use simplyfied wildcard patterns to match multiple
- * ServiceParameters with a single rule. The pattern must contain the placeholder
- * {*} for the ServiceParameter. For example
- *
- * <url ServiceParameter="adminpages.*" pattern="admin/{*}" />
- *
- * This rule will match an URL like <tt>http://example.com/index.php/admin/edituser</tt>
- * and resolve it to the page Application.pages.admin.edituser. The wildcard matching
- * is non-recursive. That means you have to add a rule for every subdirectory you
- * want to access pages in:
- *
- * <url ServiceParameter="adminpages.users.*" pattern="useradmin/{*}" />
- *
- * It is still possible to define an explicit rule for a page in the wildcard path.
- * This rule has to preceed the wildcard rule.
- *
- * You can also use parameters with wildcard patterns. The parameters are then
- * available with every matching page:
- *
- * <url ServiceParameter="adminpages.*" pattern="admin/{*}/{id}" parameters.id="\d+" />
- *
- * To enable automatic parameter encoding in a path format fro wildcard patterns you can set
- * {@setUrlFormat UrlFormat} to 'Path':
- *
- * <url ServiceParameter="adminpages.*" pattern="admin/{*}" UrlFormat="Path" />
- *
- * This will create and parse URLs of the form
- * <tt>.../index.php/admin/listuser/param1/value1/param2/value2</tt>.
- *
- * Use {@setUrlParamSeparator} to define another separator character between parameter
- * name and value. Parameter/value pairs are always separated by a '/'.
- *
- * <url ServiceParameter="adminpages.*" pattern="admin/{*}" UrlFormat="Path" UrlParamSeparator="-" />
- *
- * <tt>.../index.php/admin/listuser/param1-value1/param2-value2</tt>.
- *
+ * Since 3.1.4 you can also use simplyfied wildcard patterns to match multiple
+ * ServiceParameters with a single rule. The pattern must contain the placeholder
+ * {*} for the ServiceParameter. For example
+ *
+ * <url ServiceParameter="adminpages.*" pattern="admin/{*}" />
+ *
+ * This rule will match an URL like <tt>http://example.com/index.php/admin/edituser</tt>
+ * and resolve it to the page Application.pages.admin.edituser. The wildcard matching
+ * is non-recursive. That means you have to add a rule for every subdirectory you
+ * want to access pages in:
+ *
+ * <url ServiceParameter="adminpages.users.*" pattern="useradmin/{*}" />
+ *
+ * It is still possible to define an explicit rule for a page in the wildcard path.
+ * This rule has to preceed the wildcard rule.
+ *
+ * You can also use parameters with wildcard patterns. The parameters are then
+ * available with every matching page:
+ *
+ * <url ServiceParameter="adminpages.*" pattern="admin/{*}/{id}" parameters.id="\d+" />
+ *
+ * To enable automatic parameter encoding in a path format fro wildcard patterns you can set
+ * {@setUrlFormat UrlFormat} to 'Path':
+ *
+ * <url ServiceParameter="adminpages.*" pattern="admin/{*}" UrlFormat="Path" />
+ *
+ * This will create and parse URLs of the form
+ * <tt>.../index.php/admin/listuser/param1/value1/param2/value2</tt>.
+ *
+ * Use {@setUrlParamSeparator} to define another separator character between parameter
+ * name and value. Parameter/value pairs are always separated by a '/'.
+ *
+ * <url ServiceParameter="adminpages.*" pattern="admin/{*}" UrlFormat="Path" UrlParamSeparator="-" />
+ *
+ * <tt>.../index.php/admin/listuser/param1-value1/param2-value2</tt>.
+ *
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
* @version $Id$
* @package System.Web
@@ -449,12 +449,12 @@ class TUrlMappingPattern extends TComponent
private $_manager;
private $_caseSensitive=true;
-
- private $_isWildCardPattern=false;
-
- private $_urlFormat=THttpRequestUrlFormat::Get;
-
- private $_separator='/';
+
+ private $_isWildCardPattern=false;
+
+ private $_urlFormat=THttpRequestUrlFormat::Get;
+
+ private $_separator='/';
/**
* Constructor.
@@ -484,8 +484,8 @@ class TUrlMappingPattern extends TComponent
{
if($this->_serviceParameter===null)
throw new TConfigurationException('urlmappingpattern_serviceparameter_required', $this->getPattern());
- if(strpos($this->_serviceParameter,'*')!==false)
- $this->_isWildCardPattern=true;
+ if(strpos($this->_serviceParameter,'*')!==false)
+ $this->_isWildCardPattern=true;
}
/**
@@ -502,19 +502,19 @@ class TUrlMappingPattern extends TComponent
$params[]='{'.$key.'}';
$values[]='(?P<'.$key.'>'.$value.')';
}
- if ($this->getIsWildCardPattern()) {
- $params[]='{*}';
- // service parameter must not contain '=' and '/'
- $values[]='(?P<'.$this->getServiceID().'>[^=/]+)';
- }
+ if ($this->getIsWildCardPattern()) {
+ $params[]='{*}';
+ // service parameter must not contain '=' and '/'
+ $values[]='(?P<'.$this->getServiceID().'>[^=/]+)';
+ }
$params[]='/';
$values[]='\\/';
$regexp=str_replace($params,$values,trim($this->getPattern(),'/').'/');
- if ($this->_urlFormat===THttpRequestUrlFormat::Get)
+ if ($this->_urlFormat===THttpRequestUrlFormat::Get)
$regexp='/^'.$regexp.'$/u';
- else
+ else
$regexp='/^'.$regexp.'(?P<urlparams>.*)$/u';
-
+
if(!$this->getCaseSensitive())
$regexp.='i';
return $regexp;
@@ -629,30 +629,30 @@ class TUrlMappingPattern extends TComponent
preg_match($pattern,$request->getPathInfo(),$matches);
else
preg_match($this->getParameterizedPattern(),trim($request->getPathInfo(),'/').'/',$matches);
-
- if($this->getIsWildCardPattern() && isset($matches[$this->_serviceID]))
- $matches[$this->_serviceID]=str_replace('*',$matches[$this->_serviceID],$this->_serviceParameter);
-
- if (isset($matches['urlparams']))
- {
- $params=explode('/',$matches['urlparams']);
- if ($this->_separator==='/')
- {
- while($key=array_shift($params))
- $matches2[$key]=($value=array_shift($params)) ? $value : '';
- }
- else
- {
- array_pop($params);
- foreach($params as $param)
- {
- list($key,$value)=explode($this->_separator,$param,2);
- $matches[$key]=$value;
- }
- }
- unset($matches['urlparams']);
- }
-
+
+ if($this->getIsWildCardPattern() && isset($matches[$this->_serviceID]))
+ $matches[$this->_serviceID]=str_replace('*',$matches[$this->_serviceID],$this->_serviceParameter);
+
+ if (isset($matches['urlparams']))
+ {
+ $params=explode('/',$matches['urlparams']);
+ if ($this->_separator==='/')
+ {
+ while($key=array_shift($params))
+ $matches[$key]=($value=array_shift($params)) ? $value : '';
+ }
+ else
+ {
+ array_pop($params);
+ foreach($params as $param)
+ {
+ list($key,$value)=explode($this->_separator,$param,2);
+ $matches[$key]=$value;
+ }
+ }
+ unset($matches['urlparams']);
+ }
+
return $matches;
}
@@ -676,57 +676,57 @@ class TUrlMappingPattern extends TComponent
}
/**
- * @return boolean whether this pattern is a wildcard pattern
+ * @return boolean whether this pattern is a wildcard pattern
* @since 3.1.4
*/
- public function getIsWildCardPattern() {
- return $this->_isWildCardPattern;
- }
-
- /**
- * @return THttpRequestUrlFormat the format of URLs. Defaults to THttpRequestUrlFormat::Get.
- */
- public function getUrlFormat()
- {
- return $this->_urlFormat;
- }
-
- /**
- * Sets the format of URLs constructed and interpreted by this pattern.
- * A Get URL format is like index.php?name1=value1&name2=value2
- * while a Path URL format is like index.php/name1/value1/name2/value.
- * The separating character between name and value can be configured with
- * {@link setUrlParamSeparator} and defaults to '/'.
- * Changing the UrlFormat will affect {@link constructUrl} and how GET variables
- * are parsed.
- * @param THttpRequestUrlFormat the format of URLs.
- * @param since 3.1.4
- */
- public function setUrlFormat($value)
- {
- $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
- }
-
- /**
- * @return string separator used to separate GET variable name and value when URL format is Path. Defaults to slash '/'.
- */
- public function getUrlParamSeparator()
- {
- return $this->_separator;
- }
-
- /**
- * @param string separator used to separate GET variable name and value when URL format is Path.
- * @throws TInvalidDataValueException if the separator is not a single character
- */
- public function setUrlParamSeparator($value)
- {
- if(strlen($value)===1)
- $this->_separator=$value;
- else
- throw new TInvalidDataValueException('httprequest_separator_invalid');
- }
-
+ public function getIsWildCardPattern() {
+ return $this->_isWildCardPattern;
+ }
+
+ /**
+ * @return THttpRequestUrlFormat the format of URLs. Defaults to THttpRequestUrlFormat::Get.
+ */
+ public function getUrlFormat()
+ {
+ return $this->_urlFormat;
+ }
+
+ /**
+ * Sets the format of URLs constructed and interpreted by this pattern.
+ * A Get URL format is like index.php?name1=value1&name2=value2
+ * while a Path URL format is like index.php/name1/value1/name2/value.
+ * The separating character between name and value can be configured with
+ * {@link setUrlParamSeparator} and defaults to '/'.
+ * Changing the UrlFormat will affect {@link constructUrl} and how GET variables
+ * are parsed.
+ * @param THttpRequestUrlFormat the format of URLs.
+ * @param since 3.1.4
+ */
+ public function setUrlFormat($value)
+ {
+ $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
+ }
+
+ /**
+ * @return string separator used to separate GET variable name and value when URL format is Path. Defaults to slash '/'.
+ */
+ public function getUrlParamSeparator()
+ {
+ return $this->_separator;
+ }
+
+ /**
+ * @param string separator used to separate GET variable name and value when URL format is Path.
+ * @throws TInvalidDataValueException if the separator is not a single character
+ */
+ public function setUrlParamSeparator($value)
+ {
+ if(strlen($value)===1)
+ $this->_separator=$value;
+ else
+ throw new TInvalidDataValueException('httprequest_separator_invalid');
+ }
+
/**
* @param array list of GET items to be put in the constructed URL
* @return boolean whether this pattern IS the one for constructing the URL with the specified GET items.
@@ -770,12 +770,12 @@ class TUrlMappingPattern extends TComponent
// for the rest of the GET variables, put them in the query string
if(count($extra)>0)
{
- if ($this->_urlFormat===THttpRequestUrlFormat::Path && $this->getIsWildCardPattern()) {
- foreach ($extra as $name=>$value)
- $url.='/'.$name.$this->_separator.($encodeGetItems?rawurlencode($value):$value);
- return $url;
- }
-
+ if ($this->_urlFormat===THttpRequestUrlFormat::Path && $this->getIsWildCardPattern()) {
+ foreach ($extra as $name=>$value)
+ $url.='/'.$name.$this->_separator.($encodeGetItems?rawurlencode($value):$value);
+ return $url;
+ }
+
$url2='';
$amp=$encodeAmpersand?'&amp;':'&';
if($encodeGetItems)
diff --git a/framework/Web/UI/ActiveControls/TCallbackClientScript.php b/framework/Web/UI/ActiveControls/TCallbackClientScript.php
index 8fbdd864..d35e89a0 100644
--- a/framework/Web/UI/ActiveControls/TCallbackClientScript.php
+++ b/framework/Web/UI/ActiveControls/TCallbackClientScript.php
@@ -164,7 +164,8 @@ class TCallbackClientScript extends TApplicationComponent
*/
public function setAttribute($control, $name, $value)
{
- if ($control instanceof ISurroundable)
+ // Attributes should be applied on Surrounding tag, except for 'disabled' attribute
+ if ($control instanceof ISurroundable && strtolower($name)!=='disabled')
$control=$control->getSurroundingTagID();
$this->callClientFunction('Prado.Element.setAttribute',array($control, $name, $value));
}
diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php
index 6d44d7d7..af88620c 100644
--- a/framework/Web/UI/TTemplateManager.php
+++ b/framework/Web/UI/TTemplateManager.php
@@ -890,15 +890,19 @@ class TTemplate extends TApplicationComponent implements ITemplate
else
return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
}
- else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
+ else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
{
$value=$matches[1];
- if($value[2]==='~') // a URL
+ if($value[2]==='~')
return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
- else if($value[2]==='[')
+ elseif($value[2]==='[')
return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
- else if($value[2]==='$')
+ elseif($value[2]==='$')
return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
+ elseif($value[2]==='/') {
+ $literal = trim(substr($value,3,strlen($value)-5));
+ return array(self::CONFIG_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'");
+ }
}
else
return $value;
diff --git a/framework/Web/UI/WebControls/TBoundColumn.php b/framework/Web/UI/WebControls/TBoundColumn.php
index fdcde9b2..098ffeef 100644
--- a/framework/Web/UI/WebControls/TBoundColumn.php
+++ b/framework/Web/UI/WebControls/TBoundColumn.php
@@ -197,6 +197,7 @@ class TBoundColumn extends TDataGridColumn
$control->setItemType($item->getItemType());
}
$cell->getControls()->add($control);
+ $cell->registerObject('EditControl',$control);
}
else
{
@@ -206,7 +207,20 @@ class TBoundColumn extends TDataGridColumn
}
}
else
- $control=$cell;
+ {
+ if(($classPath=$this->getItemRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IItemDataRenderer)
+ {
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $cell->getControls()->add($control);
+ }
+ else
+ $control=$cell;
+ }
$control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
break;
default:
diff --git a/framework/Web/UI/WebControls/TDatePicker.php b/framework/Web/UI/WebControls/TDatePicker.php
index e678b046..c81d8bc1 100644
--- a/framework/Web/UI/WebControls/TDatePicker.php
+++ b/framework/Web/UI/WebControls/TDatePicker.php
@@ -487,7 +487,7 @@ class TDatePicker extends TTextBox
if(isset($values[$key.'$day']))
$day = intval($values[$key.'$day']);
else
- $day = 1;
+ $day = $date['mday'];
if(isset($values[$key.'$month']))
$month = intval($values[$key.'$month']) + 1;
@@ -961,4 +961,4 @@ class TDatePickerPositionMode extends TEnumerable
{
const Top='Top';
const Bottom='Bottom';
-} \ No newline at end of file
+}
diff --git a/framework/Web/UI/WebControls/TListControl.php b/framework/Web/UI/WebControls/TListControl.php
index c69b387e..e0c25b9e 100644
--- a/framework/Web/UI/WebControls/TListControl.php
+++ b/framework/Web/UI/WebControls/TListControl.php
@@ -1,10 +1,12 @@
<?php
+
/**
* TListControl class file
*
+ * @author Robin J. Rogge <rojaro@gmail.com>
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2008 PradoSoft
+ * @copyright Copyright &copy; 2005-2010 PradoSoft
* @license http://www.pradosoft.com/license/
* @version $Id$
* @package System.Web.UI.WebControls
@@ -15,10 +17,10 @@
*/
Prado::using('System.Web.UI.WebControls.TDataBoundControl');
Prado::using('System.Web.UI.WebControls.TListItem');
+Prado::using('System.Collections.TListItemCollection');
Prado::using('System.Collections.TAttributeCollection');
Prado::using('System.Util.TDataFieldAccessor');
-
/**
* TListControl class
*
@@ -879,151 +881,6 @@ abstract class TListControl extends TDataBoundControl implements IDataRenderer
}
/**
- * TListItemCollection class.
- *
- * TListItemCollection maintains a list of {@link TListItem} for {@link TListControl}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TListItemCollection extends TList
-{
- /**
- * Creates a list item object.
- * This method may be overriden to provide a customized list item object.
- * @param integer index where the newly created item is to be inserted at.
- * If -1, the item will be appended to the end.
- * @return TListItem list item object
- */
- public function createListItem($index=-1)
- {
- $item=$this->createNewListItem();
- if($index<0)
- $this->add($item);
- else
- $this->insertAt($index,$item);
- return $item;
- }
-
- /**
- * @return TListItem new item.
- */
- protected function createNewListItem($text=null)
- {
- $item = new TListItem;
- if($text!==null)
- $item->setText($text);
- return $item;
- }
-
- /**
- * Inserts an item into the collection.
- * @param integer the location where the item will be inserted.
- * The current item at the place and the following ones will be moved backward.
- * @param TListItem the item to be inserted.
- * @throws TInvalidDataTypeException if the item being inserted is neither a string nor TListItem
- */
- public function insertAt($index,$item)
- {
- if(is_string($item))
- $item = $this->createNewListItem($item);
- if(!($item instanceof TListItem))
- throw new TInvalidDataTypeException('listitemcollection_item_invalid',get_class($this));
- parent::insertAt($index,$item);
- }
-
- /**
- * Finds the lowest cardinal index of the item whose value is the one being looked for.
- * @param string the value to be looked for
- * @param boolean whether to look for disabled items also
- * @return integer the index of the item found, -1 if not found.
- */
- public function findIndexByValue($value,$includeDisabled=true)
- {
- $value=TPropertyValue::ensureString($value);
- $index=0;
- foreach($this as $item)
- {
- if($item->getValue()===$value && ($includeDisabled || $item->getEnabled()))
- return $index;
- $index++;
- }
- return -1;
- }
-
- /**
- * Finds the lowest cardinal index of the item whose text is the one being looked for.
- * @param string the text to be looked for
- * @param boolean whether to look for disabled items also
- * @return integer the index of the item found, -1 if not found.
- */
- public function findIndexByText($text,$includeDisabled=true)
- {
- $text=TPropertyValue::ensureString($text);
- $index=0;
- foreach($this as $item)
- {
- if($item->getText()===$text && ($includeDisabled || $item->getEnabled()))
- return $index;
- $index++;
- }
- return -1;
- }
-
- /**
- * Finds the item whose value is the one being looked for.
- * @param string the value to be looked for
- * @param boolean whether to look for disabled items also
- * @return TListItem the item found, null if not found.
- */
- public function findItemByValue($value,$includeDisabled=true)
- {
- if(($index=$this->findIndexByValue($value,$includeDisabled))>=0)
- return $this->itemAt($index);
- else
- return null;
- }
-
- /**
- * Finds the item whose text is the one being looked for.
- * @param string the text to be looked for
- * @param boolean whether to look for disabled items also
- * @return TListItem the item found, null if not found.
- */
- public function findItemByText($text,$includeDisabled=true)
- {
- if(($index=$this->findIndexByText($text,$includeDisabled))>=0)
- return $this->itemAt($index);
- else
- return null;
- }
-
- /**
- * Loads state into every item in the collection.
- * This method should only be used by framework and control developers.
- * @param array|null state to be loaded.
- */
- public function loadState($state)
- {
- $this->clear();
- if($state!==null)
- $this->copyFrom($state);
- }
-
- /**
- * Saves state of items.
- * This method should only be used by framework and control developers.
- * @return array|null the saved state
- */
- public function saveState()
- {
- return ($this->getCount()>0) ? $this->toArray() : null;
- }
-}
-
-/**
* IListControlAdapter interface
*
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>