From 95b032891d6617525636cc7b680117dbb14afba7 Mon Sep 17 00:00:00 2001 From: "christophe.boulain" <> Date: Wed, 19 Jan 2011 14:56:01 +0000 Subject: Merge last changes on "Data" from trunk --- .../Relations/TActiveRecordRelation.php | 508 ++++---- .../Data/ActiveRecord/Scaffold/TScaffoldBase.php | 3 +- framework/Data/ActiveRecord/TActiveRecord.php | 3 +- .../Data/ActiveRecord/TActiveRecordConfig.php | 2 +- .../Data/ActiveRecord/TActiveRecordGateway.php | 7 +- framework/Data/Common/Mssql/TMssqlMetaData.php | 4 +- framework/Data/Common/Mysql/TMysqlMetaData.php | 4 +- framework/Data/Common/Oracle/TOracleMetaData.php | 2 +- framework/Data/Common/Oracle/TOracleTableInfo.php | 3 +- framework/Data/Common/TDbCommandBuilder.php | 3 +- framework/Data/Common/TDbMetaData.php | 3 +- framework/Data/Common/TDbTableColumn.php | 3 +- framework/Data/Common/TDbTableInfo.php | 315 ++--- framework/Data/DataGateway/TDataGatewayCommand.php | 4 +- framework/Data/DataGateway/TSqlCriteria.php | 3 +- .../Data/SqlMap/Configuration/TParameterMap.php | 8 +- framework/Data/SqlMap/Configuration/TResultMap.php | 3 +- .../Data/SqlMap/Configuration/TResultProperty.php | 3 +- .../Configuration/TSqlMapXmlConfiguration.php | 2 +- .../Data/SqlMap/Statements/TMappedStatement.php | 3 +- .../Data/SqlMap/Statements/TPreparedStatement.php | 3 +- .../Data/SqlMap/Statements/TSimpleDynamicSql.php | 3 +- framework/Data/SqlMap/TSqlMapGateway.php | 7 +- framework/Data/SqlMap/TSqlMapManager.php | 3 +- framework/Data/TDataSourceConfig.php | 13 +- framework/Data/TDbCommand.php | 3 +- framework/Data/TDbConnection.php | 1270 ++++++++++---------- framework/Data/TDbDataReader.php | 3 +- framework/Data/TDbTransaction.php | 3 +- framework/Exceptions/TErrorHandler.php | 802 ++++++------ framework/Exceptions/messages/messages-fr.txt | 7 + framework/Exceptions/messages/messages-id.txt | 1 + framework/Exceptions/messages/messages-zh.txt | 1 + framework/Exceptions/messages/messages.txt | 19 +- 34 files changed, 1537 insertions(+), 1487 deletions(-) diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php index 7e584514..b291cbf3 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php @@ -1,254 +1,254 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Data.ActiveRecord.Relations - */ - -/** - * Load active record relationship context. - */ -Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelationContext'); - -/** - * Base class for active record relationships. - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Data.ActiveRecord.Relations - * @since 3.1 - */ -abstract class TActiveRecordRelation -{ - private $_context; - private $_criteria; - - public function __construct(TActiveRecordRelationContext $context, $criteria) - { - $this->_context = $context; - $this->_criteria = $criteria; - } - - /** - * @return TActiveRecordRelationContext - */ - protected function getContext() - { - return $this->_context; - } - - /** - * @return TActiveRecordCriteria - */ - protected function getCriteria() - { - return $this->_criteria; - } - - /** - * @return TActiveRecord - */ - protected function getSourceRecord() - { - return $this->getContext()->getSourceRecord(); - } - - abstract protected function collectForeignObjects(&$results); - - /** - * Dispatch the method calls to the source record finder object. When - * an instance of TActiveRecord or an array of TActiveRecord is returned - * the corresponding foreign objects are also fetched and assigned. - * - * Multiple relationship calls can be chain together. - * - * @param string method name called - * @param array method arguments - * @return mixed TActiveRecord or array of TActiveRecord results depending on the method called. - */ - public function __call($method,$args) - { - static $stack=array(); - - $results = call_user_func_array(array($this->getSourceRecord(),$method),$args); - $validArray = is_array($results) && count($results) > 0; - if($validArray || $results instanceof ArrayAccess || $results instanceof TActiveRecord) - { - $this->collectForeignObjects($results); - while($obj = array_pop($stack)) - $obj->collectForeignObjects($results); - } - else if($results instanceof TActiveRecordRelation) - $stack[] = $this; //call it later - else if($results === null || !$validArray) - $stacks=array(); - return $results; - } - - /** - * Fetch results for current relationship. - * @return boolean always true. - */ - public function fetchResultsInto($obj) - { - $this->collectForeignObjects($obj); - return true; - } - - /** - * Returns foreign keys in $fromRecord with source column names as key - * and foreign column names in the corresponding $matchesRecord as value. - * The method returns the first matching foreign key between these 2 records. - * @param TActiveRecord $fromRecord - * @param TActiveRecord $matchesRecord - * @return array foreign keys with source column names as key and foreign column names as value. - */ - protected function findForeignKeys($from, $matchesRecord, $loose=false) - { - $gateway = $matchesRecord->getRecordGateway(); - $recordTableInfo = $gateway->getRecordTableInfo($matchesRecord); - $matchingTableName = strtolower($recordTableInfo->getTableName()); - $matchingFullTableName = strtolower($recordTableInfo->getTableFullName()); - $tableInfo=$from; - if($from instanceof TActiveRecord) - $tableInfo = $gateway->getRecordTableInfo($from); - //find first non-empty FK - foreach($tableInfo->getForeignKeys() as $fkeys) - { - $fkTable = strtolower($fkeys['table']); - if($fkTable===$matchingTableName || $fkTable===$matchingFullTableName) - { - $hasFkField = !$loose && $this->getContext()->hasFkField(); - $key = $hasFkField ? $this->getFkFields($fkeys['keys']) : $fkeys['keys']; - if(!empty($key)) - return $key; - } - } - - //none found - $matching = $gateway->getRecordTableInfo($matchesRecord)->getTableFullName(); - throw new TActiveRecordException('ar_relations_missing_fk', - $tableInfo->getTableFullName(), $matching); - } - - /** - * @return array foreign key field names as key and object properties as value. - * @since 3.1.2 - */ - abstract public function getRelationForeignKeys(); - - /** - * Find matching foreign key fields from the 3rd element of an entry in TActiveRecord::$RELATION. - * Assume field names consist of [\w-] character sets. Prefix to the field names ending with a dot - * are ignored. - */ - private function getFkFields($fkeys) - { - $matching = array(); - preg_match_all('/\s*(\S+\.)?([\w-]+)\s*/', $this->getContext()->getFkField(), $matching); - $fields = array(); - foreach($fkeys as $fkName => $field) - { - if(in_array($fkName, $matching[2])) - $fields[$fkName] = $field; - } - return $fields; - } - - /** - * @param mixed object or array to be hashed - * @param array name of property for hashing the properties. - * @return string object hash using crc32 and serialize. - */ - protected function getObjectHash($obj, $properties) - { - $ids=array(); - foreach($properties as $property) - $ids[] = is_object($obj) ? (string)$obj->getColumnValue($property) : (string)$obj[$property]; - return serialize($ids); - } - - /** - * Fetches the foreign objects using TActiveRecord::findAllByIndex() - * @param array field names - * @param array foreign key index values. - * @return TActiveRecord[] foreign objects. - */ - protected function findForeignObjects($fields, $indexValues) - { - $finder = $this->getContext()->getForeignRecordFinder(); - return $finder->findAllByIndex($this->_criteria, $fields, $indexValues); - } - - /** - * Obtain the foreign key index values from the results. - * @param array property names - * @param array TActiveRecord results - * @return array foreign key index values. - */ - protected function getIndexValues($keys, $results) - { - if(!is_array($results) && !$results instanceof ArrayAccess) - $results = array($results); - $values=array(); - foreach($results as $result) - { - $value = array(); - foreach($keys as $name) - $value[] = $result->getColumnValue($name); - $values[] = $value; - } - return $values; - } - - /** - * Populate the results with the foreign objects found. - * @param array source results - * @param array source property names - * @param array foreign objects - * @param array foreign object field names. - */ - protected function populateResult(&$results,$properties,&$fkObjects,$fields) - { - $collections=array(); - foreach($fkObjects as $fkObject) - $collections[$this->getObjectHash($fkObject, $fields)][]=$fkObject; - $this->setResultCollection($results, $collections, $properties); - } - - /** - * Populates the result array with foreign objects (matched using foreign key hashed property values). - * @param array $results - * @param array $collections - * @param array property names - */ - protected function setResultCollection(&$results, &$collections, $properties) - { - if(is_array($results) || $results instanceof ArrayAccess) - { - for($i=0,$k=count($results);$i<$k;$i++) - $this->setObjectProperty($results[$i], $properties, $collections); - } - else - $this->setObjectProperty($results, $properties, $collections); - } - - /** - * Sets the foreign objects to the given property on the source object. - * @param TActiveRecord source object. - * @param array source properties - * @param array foreign objects. - */ - protected function setObjectProperty($source, $properties, &$collections) - { - $hash = $this->getObjectHash($source, $properties); - $prop = $this->getContext()->getProperty(); - $source->$prop=isset($collections[$hash]) ? $collections[$hash] : array(); - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2008 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.ActiveRecord.Relations + */ + +/** + * Load active record relationship context. + */ +Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelationContext'); + +/** + * Base class for active record relationships. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Data.ActiveRecord.Relations + * @since 3.1 + */ +abstract class TActiveRecordRelation +{ + private $_context; + private $_criteria; + + public function __construct(TActiveRecordRelationContext $context, $criteria) + { + $this->_context = $context; + $this->_criteria = $criteria; + } + + /** + * @return TActiveRecordRelationContext + */ + protected function getContext() + { + return $this->_context; + } + + /** + * @return TActiveRecordCriteria + */ + protected function getCriteria() + { + return $this->_criteria; + } + + /** + * @return TActiveRecord + */ + protected function getSourceRecord() + { + return $this->getContext()->getSourceRecord(); + } + + abstract protected function collectForeignObjects(&$results); + + /** + * Dispatch the method calls to the source record finder object. When + * an instance of TActiveRecord or an array of TActiveRecord is returned + * the corresponding foreign objects are also fetched and assigned. + * + * Multiple relationship calls can be chain together. + * + * @param string method name called + * @param array method arguments + * @return mixed TActiveRecord or array of TActiveRecord results depending on the method called. + */ + public function __call($method,$args) + { + static $stack=array(); + + $results = call_user_func_array(array($this->getSourceRecord(),$method),$args); + $validArray = is_array($results) && count($results) > 0; + if($validArray || $results instanceof ArrayAccess || $results instanceof TActiveRecord) + { + $this->collectForeignObjects($results); + while($obj = array_pop($stack)) + $obj->collectForeignObjects($results); + } + else if($results instanceof TActiveRecordRelation) + $stack[] = $this; //call it later + else if($results === null || !$validArray) + $stack = array(); + return $results; + } + + /** + * Fetch results for current relationship. + * @return boolean always true. + */ + public function fetchResultsInto($obj) + { + $this->collectForeignObjects($obj); + return true; + } + + /** + * Returns foreign keys in $fromRecord with source column names as key + * and foreign column names in the corresponding $matchesRecord as value. + * The method returns the first matching foreign key between these 2 records. + * @param TActiveRecord $fromRecord + * @param TActiveRecord $matchesRecord + * @return array foreign keys with source column names as key and foreign column names as value. + */ + protected function findForeignKeys($from, $matchesRecord, $loose=false) + { + $gateway = $matchesRecord->getRecordGateway(); + $recordTableInfo = $gateway->getRecordTableInfo($matchesRecord); + $matchingTableName = strtolower($recordTableInfo->getTableName()); + $matchingFullTableName = strtolower($recordTableInfo->getTableFullName()); + $tableInfo=$from; + if($from instanceof TActiveRecord) + $tableInfo = $gateway->getRecordTableInfo($from); + //find first non-empty FK + foreach($tableInfo->getForeignKeys() as $fkeys) + { + $fkTable = strtolower($fkeys['table']); + if($fkTable===$matchingTableName || $fkTable===$matchingFullTableName) + { + $hasFkField = !$loose && $this->getContext()->hasFkField(); + $key = $hasFkField ? $this->getFkFields($fkeys['keys']) : $fkeys['keys']; + if(!empty($key)) + return $key; + } + } + + //none found + $matching = $gateway->getRecordTableInfo($matchesRecord)->getTableFullName(); + throw new TActiveRecordException('ar_relations_missing_fk', + $tableInfo->getTableFullName(), $matching); + } + + /** + * @return array foreign key field names as key and object properties as value. + * @since 3.1.2 + */ + abstract public function getRelationForeignKeys(); + + /** + * Find matching foreign key fields from the 3rd element of an entry in TActiveRecord::$RELATION. + * Assume field names consist of [\w-] character sets. Prefix to the field names ending with a dot + * are ignored. + */ + private function getFkFields($fkeys) + { + $matching = array(); + preg_match_all('/\s*(\S+\.)?([\w-]+)\s*/', $this->getContext()->getFkField(), $matching); + $fields = array(); + foreach($fkeys as $fkName => $field) + { + if(in_array($fkName, $matching[2])) + $fields[$fkName] = $field; + } + return $fields; + } + + /** + * @param mixed object or array to be hashed + * @param array name of property for hashing the properties. + * @return string object hash using crc32 and serialize. + */ + protected function getObjectHash($obj, $properties) + { + $ids=array(); + foreach($properties as $property) + $ids[] = is_object($obj) ? (string)$obj->getColumnValue($property) : (string)$obj[$property]; + return serialize($ids); + } + + /** + * Fetches the foreign objects using TActiveRecord::findAllByIndex() + * @param array field names + * @param array foreign key index values. + * @return TActiveRecord[] foreign objects. + */ + protected function findForeignObjects($fields, $indexValues) + { + $finder = $this->getContext()->getForeignRecordFinder(); + return $finder->findAllByIndex($this->_criteria, $fields, $indexValues); + } + + /** + * Obtain the foreign key index values from the results. + * @param array property names + * @param array TActiveRecord results + * @return array foreign key index values. + */ + protected function getIndexValues($keys, $results) + { + if(!is_array($results) && !$results instanceof ArrayAccess) + $results = array($results); + $values=array(); + foreach($results as $result) + { + $value = array(); + foreach($keys as $name) + $value[] = $result->getColumnValue($name); + $values[] = $value; + } + return $values; + } + + /** + * Populate the results with the foreign objects found. + * @param array source results + * @param array source property names + * @param array foreign objects + * @param array foreign object field names. + */ + protected function populateResult(&$results,$properties,&$fkObjects,$fields) + { + $collections=array(); + foreach($fkObjects as $fkObject) + $collections[$this->getObjectHash($fkObject, $fields)][]=$fkObject; + $this->setResultCollection($results, $collections, $properties); + } + + /** + * Populates the result array with foreign objects (matched using foreign key hashed property values). + * @param array $results + * @param array $collections + * @param array property names + */ + protected function setResultCollection(&$results, &$collections, $properties) + { + if(is_array($results) || $results instanceof ArrayAccess) + { + for($i=0,$k=count($results);$i<$k;$i++) + $this->setObjectProperty($results[$i], $properties, $collections); + } + else + $this->setObjectProperty($results, $properties, $collections); + } + + /** + * Sets the foreign objects to the given property on the source object. + * @param TActiveRecord source object. + * @param array source properties + * @param array foreign objects. + */ + protected function setObjectProperty($source, $properties, &$collections) + { + $hash = $this->getObjectHash($source, $properties); + $prop = $this->getContext()->getProperty(); + $source->$prop=isset($collections[$hash]) ? $collections[$hash] : array(); + } +} + diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php index 9c548308..b41a593e 100644 --- a/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php +++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldBase.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @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.Scaffold @@ -65,6 +65,7 @@ abstract class TScaffoldBase extends TTemplateControl */ protected function getRecordPkValues($record) { + $data=array(); foreach($this->getTableInfo()->getColumns() as $name=>$column) { if($column->getIsPrimaryKey()) diff --git a/framework/Data/ActiveRecord/TActiveRecord.php b/framework/Data/ActiveRecord/TActiveRecord.php index af171bbd..34de431b 100644 --- a/framework/Data/ActiveRecord/TActiveRecord.php +++ b/framework/Data/ActiveRecord/TActiveRecord.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.ActiveRecord @@ -225,6 +225,7 @@ abstract class TActiveRecord extends TComponent */ public function __construct($data=array(), $connection=null) { + parent::__construct(); if($connection!==null) $this->setDbConnection($connection); $this->setupColumnMapping(); diff --git a/framework/Data/ActiveRecord/TActiveRecordConfig.php b/framework/Data/ActiveRecord/TActiveRecordConfig.php index fb57fd33..51278fc9 100644 --- a/framework/Data/ActiveRecord/TActiveRecordConfig.php +++ b/framework/Data/ActiveRecord/TActiveRecordConfig.php @@ -134,4 +134,4 @@ class TActiveRecordConfig extends TDataSourceConfig { $this->_invalidFinderResult = TPropertyValue::ensureEnum($value, 'TActiveRecordInvalidFinderResult'); } -} \ No newline at end of file +} diff --git a/framework/Data/ActiveRecord/TActiveRecordGateway.php b/framework/Data/ActiveRecord/TActiveRecordGateway.php index e588b976..534bd253 100644 --- a/framework/Data/ActiveRecord/TActiveRecordGateway.php +++ b/framework/Data/ActiveRecord/TActiveRecordGateway.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.ActiveRecord @@ -42,6 +42,7 @@ class TActiveRecordGateway extends TComponent */ public function __construct(TActiveRecordManager $manager) { + parent::__construct(); $this->_manager=$manager; } @@ -306,7 +307,7 @@ class TActiveRecordGateway extends TComponent if($column->getIsExcluded()) continue; $value = $record->getColumnValue($name); - if(!$column->getAllowNull() && $value===null && !$column->hasSequence() && !$column->getDefaultValue()) + if(!$column->getAllowNull() && $value===null && !$column->hasSequence() && ($column->getDefaultValue() === TDbTableColumn::UNDEFINED_VALUE)) { throw new TActiveRecordException( 'ar_value_must_not_be_null', get_class($record), @@ -342,7 +343,7 @@ class TActiveRecordGateway extends TComponent if($column->getIsExcluded()) continue; $value = $record->getColumnValue($name); - if(!$column->getAllowNull() && $value===null) + if(!$column->getAllowNull() && $value===null && ($column->getDefaultValue() === TDbTableColumn::UNDEFINED_VALUE)) { throw new TActiveRecordException( 'ar_value_must_not_be_null', get_class($record), diff --git a/framework/Data/Common/Mssql/TMssqlMetaData.php b/framework/Data/Common/Mssql/TMssqlMetaData.php index 8309e4ec..2751caf3 100644 --- a/framework/Data/Common/Mssql/TMssqlMetaData.php +++ b/framework/Data/Common/Mssql/TMssqlMetaData.php @@ -53,9 +53,9 @@ class TMssqlMetaData extends TDbMetaData AND t.table_name = :table EOD; if($schemaName!==null) - $sql .= ' AND t.schema_name = :schema'; + $sql .= ' AND t.table_schema = :schema'; if($catalogName!==null) - $sql .= ' AND t.catalog_name = :catalog'; + $sql .= ' AND t.table_catalog = :catalog'; $command = $this->getDbConnection()->createCommand($sql); $command->bindValue(':table', $tableName); diff --git a/framework/Data/Common/Mysql/TMysqlMetaData.php b/framework/Data/Common/Mysql/TMysqlMetaData.php index fad33cea..0e17f52c 100644 --- a/framework/Data/Common/Mysql/TMysqlMetaData.php +++ b/framework/Data/Common/Mysql/TMysqlMetaData.php @@ -263,7 +263,7 @@ class TMysqlMetaData extends TDbMetaData */ protected function getForeignConstraints($schemaName, $tableName) { - $andSchema = $schemaName !== null ? 'AND TABLE_SCHEMA = :schema' : ''; + $andSchema = $schemaName !== null ? 'AND TABLE_SCHEMA LIKE :schema' : ''; $sql = <<getDbConnection()->createCommand($sql); diff --git a/framework/Data/Common/Oracle/TOracleMetaData.php b/framework/Data/Common/Oracle/TOracleMetaData.php index 5fdf1d5c..ac119454 100644 --- a/framework/Data/Common/Oracle/TOracleMetaData.php +++ b/framework/Data/Common/Oracle/TOracleMetaData.php @@ -163,7 +163,7 @@ EOD; $command = $this->getDbConnection()->createCommand($sql); //$command->bindValue(':schema',$schemaName); //$command->bindValue(':table', $tableName); - return intval($command->queryScalar()) === 'VIEW'; + return intval($command->queryScalar() === 'VIEW'); } /** diff --git a/framework/Data/Common/Oracle/TOracleTableInfo.php b/framework/Data/Common/Oracle/TOracleTableInfo.php index c7d373b2..0a6238e0 100644 --- a/framework/Data/Common/Oracle/TOracleTableInfo.php +++ b/framework/Data/Common/Oracle/TOracleTableInfo.php @@ -5,7 +5,7 @@ * * @author Marcos Nobre * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.Common @@ -36,6 +36,7 @@ class TOracleTableInfo extends TComponent */ public function __construct($tableInfo=array(),$primary=array(),$foreign=array()) { + parent::__construct(); $this->_info=$tableInfo; $this->_primaryKeys=$primary; $this->_foreignKeys=$foreign; diff --git a/framework/Data/Common/TDbCommandBuilder.php b/framework/Data/Common/TDbCommandBuilder.php index 0dc13e7e..8619c435 100644 --- a/framework/Data/Common/TDbCommandBuilder.php +++ b/framework/Data/Common/TDbCommandBuilder.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.Common @@ -30,6 +30,7 @@ class TDbCommandBuilder extends TComponent */ public function __construct($connection=null, $tableInfo=null) { + parent::__construct(); $this->setDbConnection($connection); $this->setTableInfo($tableInfo); } diff --git a/framework/Data/Common/TDbMetaData.php b/framework/Data/Common/TDbMetaData.php index bcdf0e46..1a194056 100644 --- a/framework/Data/Common/TDbMetaData.php +++ b/framework/Data/Common/TDbMetaData.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.Common @@ -31,6 +31,7 @@ abstract class TDbMetaData extends TComponent */ public function __construct($conn) { + parent::__construct(); $this->_connection=$conn; } diff --git a/framework/Data/Common/TDbTableColumn.php b/framework/Data/Common/TDbTableColumn.php index 3bb9454b..84fa6c55 100644 --- a/framework/Data/Common/TDbTableColumn.php +++ b/framework/Data/Common/TDbTableColumn.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.Common @@ -30,6 +30,7 @@ class TDbTableColumn extends TComponent */ public function __construct($columnInfo) { + parent::__construct(); $this->_info=$columnInfo; } diff --git a/framework/Data/Common/TDbTableInfo.php b/framework/Data/Common/TDbTableInfo.php index 455dbc33..6cab9230 100644 --- a/framework/Data/Common/TDbTableInfo.php +++ b/framework/Data/Common/TDbTableInfo.php @@ -1,166 +1,167 @@ - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Data.Common - */ - -/** - * TDbTableInfo class describes the meta data of a database table. - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Data.Common - * @since 3.1 - */ -class TDbTableInfo extends TComponent -{ - private $_info=array(); - - private $_primaryKeys; - private $_foreignKeys; - - private $_columns; - +/** + * TDbTableInfo class file. + * + * @author Wei Zhuo + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2010 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data.Common + */ + +/** + * TDbTableInfo class describes the meta data of a database table. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Data.Common + * @since 3.1 + */ +class TDbTableInfo extends TComponent +{ + private $_info=array(); + + private $_primaryKeys; + private $_foreignKeys; + + private $_columns; + private $_lowercase; /** * @var null|array * @since 3.1.7 - */ - private $_names = null; - - /** - * Sets the database table meta data information. - * @param array table column information. - */ - public function __construct($tableInfo=array(),$primary=array(),$foreign=array()) - { - $this->_info=$tableInfo; - $this->_primaryKeys=$primary; - $this->_foreignKeys=$foreign; - $this->_columns=new TMap; - } - - /** - * @param TDbConnection database connection. - * @return TDbCommandBuilder new command builder - */ - public function createCommandBuilder($connection) - { - Prado::using('System.Data.Common.TDbCommandBuilder'); - return new TDbCommandBuilder($connection,$this); - } - - /** - * @param string information array key name - * @param mixed default value if information array value is null - * @return mixed information array value. - */ - protected function getInfo($name,$default=null) - { - return isset($this->_info[$name]) ? $this->_info[$name] : $default; - } - - /** - * @param string information array key name - * @param mixed new information array value. - */ - protected function setInfo($name,$value) - { - $this->_info[$name]=$value; - } - - /** - * @return string name of the table this column belongs to. - */ - public function getTableName() - { - return $this->getInfo('TableName'); - } - - /** - * @return string full name of the table, database dependent. - */ - public function getTableFullName() - { - return $this->getTableName(); - } - - /** - * @return boolean whether the table is a view, default is false. - */ - public function getIsView() - { - return $this->getInfo('IsView',false); - } - - /** - * @return TMap TDbTableColumn column meta data. - */ - public function getColumns() - { - return $this->_columns; - } - - /** - * @param string column id - * @return TDbTableColumn column information. - */ - public function getColumn($name) - { - if(($column = $this->_columns->itemAt($name))!==null) - return $column; - throw new TDbException('dbtableinfo_invalid_column_name', $name, $this->getTableFullName()); - } - - /** - * @param array list of column Id, empty to get all columns. - * @return array table column names (identifier quoted) - */ - public function getColumnNames() + */ + private $_names = null; + + /** + * Sets the database table meta data information. + * @param array table column information. + */ + public function __construct($tableInfo=array(),$primary=array(),$foreign=array()) + { + parent::__construct(); + $this->_info=$tableInfo; + $this->_primaryKeys=$primary; + $this->_foreignKeys=$foreign; + $this->_columns=new TMap; + } + + /** + * @param TDbConnection database connection. + * @return TDbCommandBuilder new command builder + */ + public function createCommandBuilder($connection) + { + Prado::using('System.Data.Common.TDbCommandBuilder'); + return new TDbCommandBuilder($connection,$this); + } + + /** + * @param string information array key name + * @param mixed default value if information array value is null + * @return mixed information array value. + */ + protected function getInfo($name,$default=null) + { + return isset($this->_info[$name]) ? $this->_info[$name] : $default; + } + + /** + * @param string information array key name + * @param mixed new information array value. + */ + protected function setInfo($name,$value) + { + $this->_info[$name]=$value; + } + + /** + * @return string name of the table this column belongs to. + */ + public function getTableName() + { + return $this->getInfo('TableName'); + } + + /** + * @return string full name of the table, database dependent. + */ + public function getTableFullName() + { + return $this->getTableName(); + } + + /** + * @return boolean whether the table is a view, default is false. + */ + public function getIsView() + { + return $this->getInfo('IsView',false); + } + + /** + * @return TMap TDbTableColumn column meta data. + */ + public function getColumns() + { + return $this->_columns; + } + + /** + * @param string column id + * @return TDbTableColumn column information. + */ + public function getColumn($name) + { + if(($column = $this->_columns->itemAt($name))!==null) + return $column; + throw new TDbException('dbtableinfo_invalid_column_name', $name, $this->getTableFullName()); + } + + /** + * @param array list of column Id, empty to get all columns. + * @return array table column names (identifier quoted) + */ + public function getColumnNames() { if($this->_names===null) - { - $this->_names=array(); - foreach($this->getColumns() as $column) + { + $this->_names=array(); + foreach($this->getColumns() as $column) $this->_names[] = $column->getColumnName(); - } - return $this->_names; - } - - /** - * @return string[] names of primary key columns. - */ - public function getPrimaryKeys() - { - return $this->_primaryKeys; - } - - /** - * @return array tuples of foreign table and column name. - */ - public function getForeignKeys() - { - return $this->_foreignKeys; - } - - /** - * @return array lowercased column key names mapped to normal column ids. - */ - public function getLowerCaseColumnNames() - { - if($this->_lowercase===null) - { - $this->_lowercase=array(); - foreach($this->getColumns()->getKeys() as $key) - $this->_lowercase[strtolower($key)] = $key; - } - return $this->_lowercase; - } -} \ No newline at end of file + } + return $this->_names; + } + + /** + * @return string[] names of primary key columns. + */ + public function getPrimaryKeys() + { + return $this->_primaryKeys; + } + + /** + * @return array tuples of foreign table and column name. + */ + public function getForeignKeys() + { + return $this->_foreignKeys; + } + + /** + * @return array lowercased column key names mapped to normal column ids. + */ + public function getLowerCaseColumnNames() + { + if($this->_lowercase===null) + { + $this->_lowercase=array(); + foreach($this->getColumns()->getKeys() as $key) + $this->_lowercase[strtolower($key)] = $key; + } + return $this->_lowercase; + } +} diff --git a/framework/Data/DataGateway/TDataGatewayCommand.php b/framework/Data/DataGateway/TDataGatewayCommand.php index e290f457..034ea36e 100644 --- a/framework/Data/DataGateway/TDataGatewayCommand.php +++ b/framework/Data/DataGateway/TDataGatewayCommand.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.DataGateway @@ -43,6 +43,7 @@ class TDataGatewayCommand extends TComponent */ public function __construct($builder) { + parent::__construct(); $this->_builder = $builder; } @@ -469,6 +470,7 @@ class TDataGatewayEventParameter extends TEventParameter public function __construct($command,$criteria) { + parent::__construct(); $this->_command=$command; $this->_criteria=$criteria; } diff --git a/framework/Data/DataGateway/TSqlCriteria.php b/framework/Data/DataGateway/TSqlCriteria.php index 14e37b35..1b85c7d3 100644 --- a/framework/Data/DataGateway/TSqlCriteria.php +++ b/framework/Data/DataGateway/TSqlCriteria.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id: TDbSqlCriteria.php 1835 2007-04-03 01:38:15Z wei $ * @package System.Data.DataGateway @@ -49,6 +49,7 @@ class TSqlCriteria extends TComponent */ public function __construct($condition=null, $parameters=array()) { + parent::__construct(); if(!is_array($parameters) && func_num_args() > 1) $parameters = array_slice(func_get_args(),1); $this->_parameters=new TAttributeCollection; diff --git a/framework/Data/SqlMap/Configuration/TParameterMap.php b/framework/Data/SqlMap/Configuration/TParameterMap.php index 4b5ee144..60b05662 100644 --- a/framework/Data/SqlMap/Configuration/TParameterMap.php +++ b/framework/Data/SqlMap/Configuration/TParameterMap.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.SqlMap.Configuration @@ -43,6 +43,7 @@ class TParameterMap extends TComponent */ public function __construct() { + parent::__construct(); $this->_properties = new TList; $this->_propertyMap = new TMap; } @@ -184,7 +185,10 @@ class TParameterMap extends TComponent { throw new TSqlMapException( 'sqlmap_unable_to_get_property_for_parameter', - $this->getID(), $property->getProperty(), get_class($object)); + $this->getID(), + $property->getProperty(), + (is_object($object) ? get_class($object) : gettype($object)) + ); } } diff --git a/framework/Data/SqlMap/Configuration/TResultMap.php b/framework/Data/SqlMap/Configuration/TResultMap.php index e85dc1aa..b20a81f6 100644 --- a/framework/Data/SqlMap/Configuration/TResultMap.php +++ b/framework/Data/SqlMap/Configuration/TResultMap.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.SqlMap.Configuration @@ -51,6 +51,7 @@ class TResultMap extends TComponent */ public function __construct() { + parent::__construct(); $this->_columns=new TMap; } diff --git a/framework/Data/SqlMap/Configuration/TResultProperty.php b/framework/Data/SqlMap/Configuration/TResultProperty.php index 7316ef0b..24401812 100644 --- a/framework/Data/SqlMap/Configuration/TResultProperty.php +++ b/framework/Data/SqlMap/Configuration/TResultProperty.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.SqlMap.Configuration @@ -57,6 +57,7 @@ class TResultProperty extends TComponent */ public function __construct($resultMap=null) { + parent::__construct(); if($resultMap instanceof TResultMap) $this->_hostResultMapID = $resultMap->getID(); } diff --git a/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php b/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php index c49a4219..2448659a 100644 --- a/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php +++ b/framework/Data/SqlMap/Configuration/TSqlMapXmlConfiguration.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.SqlMap.Configuration diff --git a/framework/Data/SqlMap/Statements/TMappedStatement.php b/framework/Data/SqlMap/Statements/TMappedStatement.php index c4bb53dd..7aab3510 100644 --- a/framework/Data/SqlMap/Statements/TMappedStatement.php +++ b/framework/Data/SqlMap/Statements/TMappedStatement.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.SqlMap.Statements @@ -116,6 +116,7 @@ class TMappedStatement extends TComponent implements IMappedStatement */ public function __construct(TSqlMapManager $sqlMap, TSqlMapStatement $statement) { + parent::__construct(); $this->_manager = $sqlMap; $this->_statement = $statement; $this->_command = new TPreparedCommand(); diff --git a/framework/Data/SqlMap/Statements/TPreparedStatement.php b/framework/Data/SqlMap/Statements/TPreparedStatement.php index 7d862378..c9faf4ee 100644 --- a/framework/Data/SqlMap/Statements/TPreparedStatement.php +++ b/framework/Data/SqlMap/Statements/TPreparedStatement.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.SqlMap.Statements @@ -26,6 +26,7 @@ class TPreparedStatement extends TComponent public function __construct() { + parent::__construct(); $this->_parameterNames=new TList; $this->_parameterValues=new TMap; } diff --git a/framework/Data/SqlMap/Statements/TSimpleDynamicSql.php b/framework/Data/SqlMap/Statements/TSimpleDynamicSql.php index 5d85ded9..5335c41c 100644 --- a/framework/Data/SqlMap/Statements/TSimpleDynamicSql.php +++ b/framework/Data/SqlMap/Statements/TSimpleDynamicSql.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.SqlMap.Statements @@ -24,6 +24,7 @@ class TSimpleDynamicSql extends TStaticSql public function __construct($mappings) { + parent::__construct(); $this->_mappings = $mappings; } diff --git a/framework/Data/SqlMap/TSqlMapGateway.php b/framework/Data/SqlMap/TSqlMapGateway.php index 97b31b50..3a19d155 100644 --- a/framework/Data/SqlMap/TSqlMapGateway.php +++ b/framework/Data/SqlMap/TSqlMapGateway.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.SqlMap @@ -36,6 +36,7 @@ class TSqlMapGateway extends TComponent public function __construct($manager) { + parent::__construct(); $this->_manager=$manager; } @@ -122,7 +123,7 @@ class TSqlMapGateway extends TComponent * @param string The name of the sql statement to execute. * @param mixed The object used to set the parameters in the SQL. * @param integer The maximum number of objects to store in each page. - * @param integer The number of the page to initially load into the list. + * @param integer The number of the page to initially load into the list. * @return TPagedList A PaginatedList of beans containing the rows. */ public function queryForPagedList($statementName, $parameter=null, $pageSize=10, $page=0) @@ -143,7 +144,7 @@ class TSqlMapGateway extends TComponent * @param callback Row delegate handler, a valid callback required. * @param mixed The object used to set the parameters in the SQL. * @param integer The maximum number of objects to store in each page. - * @param integer The number of the page to initially load into the list. + * @param integer The number of the page to initially load into the list. * @return TPagedList A PaginatedList of beans containing the rows. */ public function queryForPagedListWithRowDelegate($statementName,$delegate, $parameter=null, $pageSize=10, $page=0) diff --git a/framework/Data/SqlMap/TSqlMapManager.php b/framework/Data/SqlMap/TSqlMapManager.php index 432c1c5e..0af90a3d 100644 --- a/framework/Data/SqlMap/TSqlMapManager.php +++ b/framework/Data/SqlMap/TSqlMapManager.php @@ -4,7 +4,7 @@ * * @author Wei Zhuo * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data.SqlMap @@ -60,6 +60,7 @@ class TSqlMapManager extends TComponent */ public function __construct($connection=null) { + parent::__construct(); $this->_connection=$connection; $this->_mappedStatements=new TMap; diff --git a/framework/Data/TDataSourceConfig.php b/framework/Data/TDataSourceConfig.php index 53a5ef22..bea15ec4 100644 --- a/framework/Data/TDataSourceConfig.php +++ b/framework/Data/TDataSourceConfig.php @@ -58,13 +58,13 @@ class TDataSourceConfig extends TModule */ public function init($xml) { - if($prop=$xml->getElementByTagName('database')) - { - $db=$this->getDbConnection(); - foreach($prop->getAttributes() as $name=>$value) - $db->setSubproperty($name,$value); + if($prop=$xml->getElementByTagName('database')) + { + $db=$this->getDbConnection(); + foreach($prop->getAttributes() as $name=>$value) + $db->setSubproperty($name,$value); + } } - } /** * The module ID of another TDataSourceConfig. The {@link getDbConnection DbConnection} @@ -153,4 +153,3 @@ class TDataSourceConfig extends TModule throw new TConfigurationException('datasource_dbconnection_invalid',$id); } } - diff --git a/framework/Data/TDbCommand.php b/framework/Data/TDbCommand.php index d09c53f4..749d3ec3 100644 --- a/framework/Data/TDbCommand.php +++ b/framework/Data/TDbCommand.php @@ -4,7 +4,7 @@ * * @author Qiang Xue * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data @@ -49,6 +49,7 @@ class TDbCommand extends TComponent */ public function __construct(TDbConnection $connection,$text) { + parent::__construct(); $this->_connection=$connection; $this->setText($text); } diff --git a/framework/Data/TDbConnection.php b/framework/Data/TDbConnection.php index 4726083c..1eba022b 100644 --- a/framework/Data/TDbConnection.php +++ b/framework/Data/TDbConnection.php @@ -1,634 +1,640 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Data - */ - -Prado::using('System.Data.TDbTransaction'); -Prado::using('System.Data.TDbCommand'); - -/** - * TDbConnection class - * - * TDbConnection represents a connection to a database. - * - * TDbConnection works together with {@link TDbCommand}, {@link TDbDataReader} - * and {@link TDbTransaction} to provide data access to various DBMS - * in a common set of APIs. They are a thin wrapper of the {@link http://www.php.net/manual/en/ref.pdo.php PDO} - * PHP extension. - * - * To establish a connection, set {@link setActive Active} to true after - * 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) - * 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, ... - * - * The following example shows how to create a TDbConnection instance and establish - * the actual connection: - * - * $connection=new TDbConnection($dsn,$username,$password); - * $connection->Active=true; - * - * - * After the DB connection is established, one can execute an SQL statement like the following: - * - * $command=$connection->createCommand($sqlStatement); - * $command->execute(); // a non-query SQL statement execution - * // or execute an SQL query and fetch the result set - * $reader=$command->query(); - * - * // each $row is an array representing a row of data - * foreach($reader as $row) ... - * - * - * One can do prepared SQL execution and bind parameters to the prepared SQL: - * - * $command=$connection->createCommand($sqlStatement); - * $command->bindParameter($name1,$value1); - * $command->bindParameter($name2,$value2); - * $command->execute(); - * - * - * To use transaction, do like the following: - * - * $transaction=$connection->beginTransaction(); - * try - * { - * $connection->createCommand($sql1)->execute(); - * $connection->createCommand($sql2)->execute(); - * //.... other SQL executions - * $transaction->commit(); - * } - * catch(Exception $e) - * { - * $transaction->rollBack(); - * } - * - * - * TDbConnection provides a set of methods to support setting and querying - * of certain DBMS attributes, such as {@link getNullConversion NullConversion}. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Data - * @since 3.0 - */ -class TDbConnection extends TComponent -{ - /** - * - * @since 3.1.7 - */ - const DEFAULT_TRANSACTION_CLASS = 'System.Data.TDbTransaction'; - - private $_dsn=''; - private $_username=''; - private $_password=''; - private $_charset=''; - private $_attributes=array(); - private $_active=false; - private $_pdo=null; - 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. - * @param string Charset used for DB Connection (MySql & pgsql only). If not set, will use the default charset of your database server - * @see http://www.php.net/manual/en/function.PDO-construct.php - */ - public function __construct($dsn='',$username='',$password='', $charset='') - { - $this->_dsn=$dsn; - $this->_username=$username; - $this->_password=$password; - $this->_charset=$charset; - } - - /** - * Close the connection when serializing. - */ - public function __sleep() - { - $this->close(); - return array_keys(get_object_vars($this)); - } - - /** - * @return array list of available PDO drivers - * @see http://www.php.net/manual/en/function.PDO-getAvailableDrivers.php - */ - public static function getAvailableDrivers() - { - return PDO::getAvailableDrivers(); - } - - /** - * @return boolean whether the DB connection is established - */ - public function getActive() - { - return $this->_active; - } - - /** - * Open or close the DB connection. - * @param boolean whether to open or close DB connection - * @throws TDbException if connection fails - */ - public function setActive($value) - { - $value=TPropertyValue::ensureBoolean($value); - if($value!==$this->_active) - { - if($value) - $this->open(); - else - $this->close(); - } - } - - /** - * Opens DB connection if it is currently not - * @throws TDbException if connection fails - */ - protected function open() - { - if($this->_pdo===null) - { - try - { - $this->_pdo=new PDO($this->getConnectionString(),$this->getUsername(), + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2010 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Data + */ + +Prado::using('System.Data.TDbTransaction'); +Prado::using('System.Data.TDbCommand'); + +/** + * TDbConnection class + * + * TDbConnection represents a connection to a database. + * + * TDbConnection works together with {@link TDbCommand}, {@link TDbDataReader} + * and {@link TDbTransaction} to provide data access to various DBMS + * in a common set of APIs. They are a thin wrapper of the {@link http://www.php.net/manual/en/ref.pdo.php PDO} + * PHP extension. + * + * To establish a connection, set {@link setActive Active} to true after + * 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) + * 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, ... + * + * The following example shows how to create a TDbConnection instance and establish + * the actual connection: + * + * $connection=new TDbConnection($dsn,$username,$password); + * $connection->Active=true; + * + * + * After the DB connection is established, one can execute an SQL statement like the following: + * + * $command=$connection->createCommand($sqlStatement); + * $command->execute(); // a non-query SQL statement execution + * // or execute an SQL query and fetch the result set + * $reader=$command->query(); + * + * // each $row is an array representing a row of data + * foreach($reader as $row) ... + * + * + * One can do prepared SQL execution and bind parameters to the prepared SQL: + * + * $command=$connection->createCommand($sqlStatement); + * $command->bindParameter($name1,$value1); + * $command->bindParameter($name2,$value2); + * $command->execute(); + * + * + * To use transaction, do like the following: + * + * $transaction=$connection->beginTransaction(); + * try + * { + * $connection->createCommand($sql1)->execute(); + * $connection->createCommand($sql2)->execute(); + * //.... other SQL executions + * $transaction->commit(); + * } + * catch(Exception $e) + * { + * $transaction->rollBack(); + * } + * + * + * TDbConnection provides a set of methods to support setting and querying + * of certain DBMS attributes, such as {@link getNullConversion NullConversion}. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Data + * @since 3.0 + */ +class TDbConnection extends TComponent +{ + /** + * + * @since 3.1.7 + */ + const DEFAULT_TRANSACTION_CLASS = 'System.Data.TDbTransaction'; + + private $_dsn=''; + private $_username=''; + private $_password=''; + private $_charset=''; + private $_attributes=array(); + private $_active=false; + private $_pdo=null; + 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. + * @param string Charset used for DB Connection (MySql & pgsql only). If not set, will use the default charset of your database server + * @see http://www.php.net/manual/en/function.PDO-construct.php + */ + public function __construct($dsn='',$username='',$password='', $charset='') + { + parent::__construct(); + $this->_dsn=$dsn; + $this->_username=$username; + $this->_password=$password; + $this->_charset=$charset; + } + + /** + * Close the connection when serializing. + */ + public function __sleep() + { + $this->close(); + return array_keys(get_object_vars($this)); + } + + /** + * @return array list of available PDO drivers + * @see http://www.php.net/manual/en/function.PDO-getAvailableDrivers.php + */ + public static function getAvailableDrivers() + { + return PDO::getAvailableDrivers(); + } + + /** + * @return boolean whether the DB connection is established + */ + public function getActive() + { + return $this->_active; + } + + /** + * Open or close the DB connection. + * @param boolean whether to open or close DB connection + * @throws TDbException if connection fails + */ + public function setActive($value) + { + $value=TPropertyValue::ensureBoolean($value); + if($value!==$this->_active) + { + if($value) + $this->open(); + else + $this->close(); + } + } + + /** + * Opens DB connection if it is currently not + * @throws TDbException if connection fails + */ + protected function open() + { + if($this->_pdo===null) + { + try + { + $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); - $this->_active=true; - $this->setConnectionCharset(); - } - catch(PDOException $e) - { - throw new TDbException('dbconnection_open_failed',$e->getMessage()); - } - } - } - - /** - * Closes the currently active DB connection. - * It does nothing if the connection is already closed. - */ - protected function close() - { - $this->_pdo=null; - $this->_active=false; - } - - /* - * Set the database connection charset. - * Only MySql databases are supported for now. - * @since 3.1.2 - */ - protected function setConnectionCharset() - { - if ($this->_charset === '' || $this->_active === false) - return; - switch ($this->_pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) - { - case 'mysql': - $stmt = $this->_pdo->prepare('SET NAMES ?'); - break; - case 'pgsql': - $stmt = $this->_pdo->prepare('SET client_encoding TO ?'); - break; - } - $stmt->execute(array($this->_charset)); - } - - /** - * @return string The Data Source Name, or DSN, contains the information required to connect to the database. - */ - public function getConnectionString() - { - return $this->_dsn; - } - - /** - * @param string The Data Source Name, or DSN, contains the information required to connect to the database. - * @see http://www.php.net/manual/en/function.PDO-construct.php - */ - public function setConnectionString($value) - { - $this->_dsn=$value; - } - - /** - * @return string the username for establishing DB connection. Defaults to empty string. - */ - public function getUsername() - { - return $this->_username; - } - - /** - * @param string the username for establishing DB connection - */ - public function setUsername($value) - { - $this->_username=$value; - } - - /** - * @return string the password for establishing DB connection. Defaults to empty string. - */ - public function getPassword() - { - return $this->_password; - } - - /** - * @param string the password for establishing DB connection - */ - public function setPassword($value) - { - $this->_password=$value; - } - - /** - * @return string the charset used for database connection. Defaults to emtpy string. - */ - public function getCharset () - { - return $this->_charset; - } - - /** - * @param string the charset used for database connection - */ - public function setCharset ($value) - { - $this->_charset=$value; - $this->setConnectionCharset(); - } - - /** - * @return PDO the PDO instance, null if the connection is not established yet - */ - public function getPdoInstance() - { - return $this->_pdo; - } - - /** - * Creates a command for execution. - * @param string SQL statement associated with the new command. - * @return TDbCommand the DB command - * @throws TDbException if the connection is not active - */ - public function createCommand($sql) - { - if($this->getActive()) - return new TDbCommand($this,$sql); - else - throw new TDbException('dbconnection_connection_inactive'); - } - - /** - * @return TDbTransaction the currently active transaction. Null if no active transaction. - */ - public function getCurrentTransaction() - { - if($this->_transaction!==null) - { - if($this->_transaction->getActive()) - return $this->_transaction; - } - return null; - } - - /** - * Starts a transaction. - * @return TDbTransaction the transaction initiated - * @throws TDbException if the connection is not active - */ - public function beginTransaction() - { - if($this->getActive()) - { - $this->_pdo->beginTransaction(); - 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 - * @see http://www.php.net/manual/en/function.PDO-lastInsertId.php - */ - public function getLastInsertID($sequenceName='') - { - if($this->getActive()) - return $this->_pdo->lastInsertId($sequenceName); - else - throw new TDbException('dbconnection_connection_inactive'); - } - - /** - * Quotes a string for use in a query. - * @param string string to be quoted - * @return string the properly quoted string - * @see http://www.php.net/manual/en/function.PDO-quote.php - */ - public function quoteString($str) - { - if($this->getActive()) - return $this->_pdo->quote($str); - else - throw new TDbException('dbconnection_connection_inactive'); - } - - /** - * @return TDbColumnCaseMode the case of the column names - */ - public function getColumnCase() - { - switch($this->getAttribute(PDO::ATTR_CASE)) - { - case PDO::CASE_NATURAL: - return TDbColumnCaseMode::Preserved; - case PDO::CASE_LOWER: - return TDbColumnCaseMode::LowerCase; - case PDO::CASE_UPPER: - return TDbColumnCaseMode::UpperCase; - } - } - - /** - * @param TDbColumnCaseMode the case of the column names - */ - public function setColumnCase($value) - { - switch(TPropertyValue::ensureEnum($value,'TDbColumnCaseMode')) - { - case TDbColumnCaseMode::Preserved: - $value=PDO::CASE_NATURAL; - break; - case TDbColumnCaseMode::LowerCase: - $value=PDO::CASE_LOWER; - break; - case TDbColumnCaseMode::UpperCase: - $value=PDO::CASE_UPPER; - break; - } - $this->setAttribute(PDO::ATTR_CASE,$value); - } - - /** - * @return TDbNullConversionMode how the null and empty strings are converted - */ - public function getNullConversion() - { - switch($this->getAttribute(PDO::ATTR_ORACLE_NULLS)) - { - case PDO::NULL_NATURAL: - return TDbNullConversionMode::Preserved; - case PDO::NULL_EMPTY_STRING: - return TDbNullConversionMode::EmptyStringToNull; - case PDO::NULL_TO_STRING: - return TDbNullConversionMode::NullToEmptyString; - } - } - - /** - * @param TDbNullConversionMode how the null and empty strings are converted - */ - public function setNullConversion($value) - { - switch(TPropertyValue::ensureEnum($value,'TDbNullConversionMode')) - { - case TDbNullConversionMode::Preserved: - $value=PDO::NULL_NATURAL; - break; - case TDbNullConversionMode::EmptyStringToNull: - $value=PDO::NULL_EMPTY_STRING; - break; - case TDbNullConversionMode::NullToEmptyString: - $value=PDO::NULL_TO_STRING; - break; - } - $this->setAttribute(PDO::ATTR_ORACLE_NULLS,$value); - } - - /** - * @return boolean whether creating or updating a DB record will be automatically committed. - * Some DBMS (such as sqlite) may not support this feature. - */ - public function getAutoCommit() - { - return $this->getAttribute(PDO::ATTR_AUTOCOMMIT); - } - - /** - * @param boolean whether creating or updating a DB record will be automatically committed. - * Some DBMS (such as sqlite) may not support this feature. - */ - public function setAutoCommit($value) - { - $this->setAttribute(PDO::ATTR_AUTOCOMMIT,TPropertyValue::ensureBoolean($value)); - } - - /** - * @return boolean whether the connection is persistent or not - * Some DBMS (such as sqlite) may not support this feature. - */ - public function getPersistent() - { - return $this->getAttribute(PDO::ATTR_PERSISTENT); - } - - /** - * @param boolean whether the connection is persistent or not - * Some DBMS (such as sqlite) may not support this feature. - */ - public function setPersistent($value) - { - return $this->setAttribute(PDO::ATTR_PERSISTENT,TPropertyValue::ensureBoolean($value)); - } - - /** - * @return string name of the DB driver - */ - public function getDriverName() - { - return $this->getAttribute(PDO::ATTR_DRIVER_NAME); - } - - /** - * @return string the version information of the DB driver - */ - public function getClientVersion() - { - return $this->getAttribute(PDO::ATTR_CLIENT_VERSION); - } - - /** - * @return string the status of the connection - * Some DBMS (such as sqlite) may not support this feature. - */ - public function getConnectionStatus() - { - return $this->getAttribute(PDO::ATTR_CONNECTION_STATUS); - } - - /** - * @return boolean whether the connection performs data prefetching - */ - public function getPrefetch() - { - return $this->getAttribute(PDO::ATTR_PREFETCH); - } - - /** - * @return string the information of DBMS server - */ - public function getServerInfo() - { - return $this->getAttribute(PDO::ATTR_SERVER_INFO); - } - - /** - * @return string the version information of DBMS server - */ - public function getServerVersion() - { - return $this->getAttribute(PDO::ATTR_SERVER_VERSION); - } - - /** - * @return int timeout settings for the connection - */ - public function getTimeout() - { - return $this->getAttribute(PDO::ATTR_TIMEOUT); - } - - /** - * Obtains a specific DB connection attribute information. - * @param int the attribute to be queried - * @return mixed the corresponding attribute information - * @see http://www.php.net/manual/en/function.PDO-getAttribute.php - */ - public function getAttribute($name) - { - if($this->getActive()) - return $this->_pdo->getAttribute($name); - else - throw new TDbException('dbconnection_connection_inactive'); - } - - /** - * Sets an attribute on the database connection. - * @param int the attribute to be set - * @param mixed the attribute value - * @see http://www.php.net/manual/en/function.PDO-setAttribute.php - */ - public function setAttribute($name,$value) - { - if($this->_pdo instanceof PDO) - $this->_pdo->setAttribute($name,$value); - else - $this->_attributes[$name]=$value; - } -} - -/** - * TDbColumnCaseMode - * - * @author Qiang Xue - * @version $Id$ - * @package System.Data - * @since 3.0 - */ -class TDbColumnCaseMode extends TEnumerable -{ - /** - * Column name cases are kept as is from the database - */ - const Preserved='Preserved'; - /** - * Column names are converted to lower case - */ - const LowerCase='LowerCase'; - /** - * Column names are converted to upper case - */ - const UpperCase='UpperCase'; -} - -/** - * TDbNullConversionMode - * - * @author Qiang Xue - * @version $Id$ - * @package System.Data - * @since 3.0 - */ -class TDbNullConversionMode extends TEnumerable -{ - /** - * No conversion is performed for null and empty values. - */ - const Preserved='Preserved'; - /** - * NULL is converted to empty string - */ - const NullToEmptyString='NullToEmptyString'; - /** - * Empty string is converted to NULL - */ - const EmptyStringToNull='EmptyStringToNull'; -} - -?> + @$this->_pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->_active=true; + $this->setConnectionCharset(); + } + catch(PDOException $e) + { + throw new TDbException('dbconnection_open_failed',$e->getMessage()); + } + } + } + + /** + * Closes the currently active DB connection. + * It does nothing if the connection is already closed. + */ + protected function close() + { + $this->_pdo=null; + $this->_active=false; + } + + /* + * Set the database connection charset. + * Only MySql databases are supported for now. + * @since 3.1.2 + */ + protected function setConnectionCharset() + { + if ($this->_charset === '' || $this->_active === false) + return; + switch ($this->_pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) + { + case 'mysql': + $stmt = $this->_pdo->prepare('SET NAMES ?'); + break; + case 'pgsql': + $stmt = $this->_pdo->prepare('SET client_encoding TO ?'); + break; + case 'sqlite': + $stmt = $pdo->prepare ('SET NAMES ?'); + break; + default: + throw new TDbException('dbconnection_unsupported_driver_charset', $driver); + } + $stmt->execute(array($this->_charset)); + } + + /** + * @return string The Data Source Name, or DSN, contains the information required to connect to the database. + */ + public function getConnectionString() + { + return $this->_dsn; + } + + /** + * @param string The Data Source Name, or DSN, contains the information required to connect to the database. + * @see http://www.php.net/manual/en/function.PDO-construct.php + */ + public function setConnectionString($value) + { + $this->_dsn=$value; + } + + /** + * @return string the username for establishing DB connection. Defaults to empty string. + */ + public function getUsername() + { + return $this->_username; + } + + /** + * @param string the username for establishing DB connection + */ + public function setUsername($value) + { + $this->_username=$value; + } + + /** + * @return string the password for establishing DB connection. Defaults to empty string. + */ + public function getPassword() + { + return $this->_password; + } + + /** + * @param string the password for establishing DB connection + */ + public function setPassword($value) + { + $this->_password=$value; + } + + /** + * @return string the charset used for database connection. Defaults to emtpy string. + */ + public function getCharset () + { + return $this->_charset; + } + + /** + * @param string the charset used for database connection + */ + public function setCharset ($value) + { + $this->_charset=$value; + $this->setConnectionCharset(); + } + + /** + * @return PDO the PDO instance, null if the connection is not established yet + */ + public function getPdoInstance() + { + return $this->_pdo; + } + + /** + * Creates a command for execution. + * @param string SQL statement associated with the new command. + * @return TDbCommand the DB command + * @throws TDbException if the connection is not active + */ + public function createCommand($sql) + { + if($this->getActive()) + return new TDbCommand($this,$sql); + else + throw new TDbException('dbconnection_connection_inactive'); + } + + /** + * @return TDbTransaction the currently active transaction. Null if no active transaction. + */ + public function getCurrentTransaction() + { + if($this->_transaction!==null) + { + if($this->_transaction->getActive()) + return $this->_transaction; + } + return null; + } + + /** + * Starts a transaction. + * @return TDbTransaction the transaction initiated + * @throws TDbException if the connection is not active + */ + public function beginTransaction() + { + if($this->getActive()) + { + $this->_pdo->beginTransaction(); + 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 + * @see http://www.php.net/manual/en/function.PDO-lastInsertId.php + */ + public function getLastInsertID($sequenceName='') + { + if($this->getActive()) + return $this->_pdo->lastInsertId($sequenceName); + else + throw new TDbException('dbconnection_connection_inactive'); + } + + /** + * Quotes a string for use in a query. + * @param string string to be quoted + * @return string the properly quoted string + * @see http://www.php.net/manual/en/function.PDO-quote.php + */ + public function quoteString($str) + { + if($this->getActive()) + return $this->_pdo->quote($str); + else + throw new TDbException('dbconnection_connection_inactive'); + } + + /** + * @return TDbColumnCaseMode the case of the column names + */ + public function getColumnCase() + { + switch($this->getAttribute(PDO::ATTR_CASE)) + { + case PDO::CASE_NATURAL: + return TDbColumnCaseMode::Preserved; + case PDO::CASE_LOWER: + return TDbColumnCaseMode::LowerCase; + case PDO::CASE_UPPER: + return TDbColumnCaseMode::UpperCase; + } + } + + /** + * @param TDbColumnCaseMode the case of the column names + */ + public function setColumnCase($value) + { + switch(TPropertyValue::ensureEnum($value,'TDbColumnCaseMode')) + { + case TDbColumnCaseMode::Preserved: + $value=PDO::CASE_NATURAL; + break; + case TDbColumnCaseMode::LowerCase: + $value=PDO::CASE_LOWER; + break; + case TDbColumnCaseMode::UpperCase: + $value=PDO::CASE_UPPER; + break; + } + $this->setAttribute(PDO::ATTR_CASE,$value); + } + + /** + * @return TDbNullConversionMode how the null and empty strings are converted + */ + public function getNullConversion() + { + switch($this->getAttribute(PDO::ATTR_ORACLE_NULLS)) + { + case PDO::NULL_NATURAL: + return TDbNullConversionMode::Preserved; + case PDO::NULL_EMPTY_STRING: + return TDbNullConversionMode::EmptyStringToNull; + case PDO::NULL_TO_STRING: + return TDbNullConversionMode::NullToEmptyString; + } + } + + /** + * @param TDbNullConversionMode how the null and empty strings are converted + */ + public function setNullConversion($value) + { + switch(TPropertyValue::ensureEnum($value,'TDbNullConversionMode')) + { + case TDbNullConversionMode::Preserved: + $value=PDO::NULL_NATURAL; + break; + case TDbNullConversionMode::EmptyStringToNull: + $value=PDO::NULL_EMPTY_STRING; + break; + case TDbNullConversionMode::NullToEmptyString: + $value=PDO::NULL_TO_STRING; + break; + } + $this->setAttribute(PDO::ATTR_ORACLE_NULLS,$value); + } + + /** + * @return boolean whether creating or updating a DB record will be automatically committed. + * Some DBMS (such as sqlite) may not support this feature. + */ + public function getAutoCommit() + { + return $this->getAttribute(PDO::ATTR_AUTOCOMMIT); + } + + /** + * @param boolean whether creating or updating a DB record will be automatically committed. + * Some DBMS (such as sqlite) may not support this feature. + */ + public function setAutoCommit($value) + { + $this->setAttribute(PDO::ATTR_AUTOCOMMIT,TPropertyValue::ensureBoolean($value)); + } + + /** + * @return boolean whether the connection is persistent or not + * Some DBMS (such as sqlite) may not support this feature. + */ + public function getPersistent() + { + return $this->getAttribute(PDO::ATTR_PERSISTENT); + } + + /** + * @param boolean whether the connection is persistent or not + * Some DBMS (such as sqlite) may not support this feature. + */ + public function setPersistent($value) + { + return $this->setAttribute(PDO::ATTR_PERSISTENT,TPropertyValue::ensureBoolean($value)); + } + + /** + * @return string name of the DB driver + */ + public function getDriverName() + { + return $this->getAttribute(PDO::ATTR_DRIVER_NAME); + } + + /** + * @return string the version information of the DB driver + */ + public function getClientVersion() + { + return $this->getAttribute(PDO::ATTR_CLIENT_VERSION); + } + + /** + * @return string the status of the connection + * Some DBMS (such as sqlite) may not support this feature. + */ + public function getConnectionStatus() + { + return $this->getAttribute(PDO::ATTR_CONNECTION_STATUS); + } + + /** + * @return boolean whether the connection performs data prefetching + */ + public function getPrefetch() + { + return $this->getAttribute(PDO::ATTR_PREFETCH); + } + + /** + * @return string the information of DBMS server + */ + public function getServerInfo() + { + return $this->getAttribute(PDO::ATTR_SERVER_INFO); + } + + /** + * @return string the version information of DBMS server + */ + public function getServerVersion() + { + return $this->getAttribute(PDO::ATTR_SERVER_VERSION); + } + + /** + * @return int timeout settings for the connection + */ + public function getTimeout() + { + return $this->getAttribute(PDO::ATTR_TIMEOUT); + } + + /** + * Obtains a specific DB connection attribute information. + * @param int the attribute to be queried + * @return mixed the corresponding attribute information + * @see http://www.php.net/manual/en/function.PDO-getAttribute.php + */ + public function getAttribute($name) + { + if($this->getActive()) + return $this->_pdo->getAttribute($name); + else + throw new TDbException('dbconnection_connection_inactive'); + } + + /** + * Sets an attribute on the database connection. + * @param int the attribute to be set + * @param mixed the attribute value + * @see http://www.php.net/manual/en/function.PDO-setAttribute.php + */ + public function setAttribute($name,$value) + { + if($this->_pdo instanceof PDO) + $this->_pdo->setAttribute($name,$value); + else + $this->_attributes[$name]=$value; + } +} + +/** + * TDbColumnCaseMode + * + * @author Qiang Xue + * @version $Id$ + * @package System.Data + * @since 3.0 + */ +class TDbColumnCaseMode extends TEnumerable +{ + /** + * Column name cases are kept as is from the database + */ + const Preserved='Preserved'; + /** + * Column names are converted to lower case + */ + const LowerCase='LowerCase'; + /** + * Column names are converted to upper case + */ + const UpperCase='UpperCase'; +} + +/** + * TDbNullConversionMode + * + * @author Qiang Xue + * @version $Id$ + * @package System.Data + * @since 3.0 + */ +class TDbNullConversionMode extends TEnumerable +{ + /** + * No conversion is performed for null and empty values. + */ + const Preserved='Preserved'; + /** + * NULL is converted to empty string + */ + const NullToEmptyString='NullToEmptyString'; + /** + * Empty string is converted to NULL + */ + const EmptyStringToNull='EmptyStringToNull'; +} + +?> diff --git a/framework/Data/TDbDataReader.php b/framework/Data/TDbDataReader.php index 7b54414e..4a323024 100644 --- a/framework/Data/TDbDataReader.php +++ b/framework/Data/TDbDataReader.php @@ -4,7 +4,7 @@ * * @author Qiang Xue * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data @@ -47,6 +47,7 @@ class TDbDataReader extends TComponent implements Iterator */ public function __construct(TDbCommand $command) { + parent::__construct(); $this->_statement=$command->getPdoStatement(); $this->_statement->setFetchMode(PDO::FETCH_ASSOC); } diff --git a/framework/Data/TDbTransaction.php b/framework/Data/TDbTransaction.php index 60b14a55..7c646833 100644 --- a/framework/Data/TDbTransaction.php +++ b/framework/Data/TDbTransaction.php @@ -4,7 +4,7 @@ * * @author Qiang Xue * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2008 PradoSoft + * @copyright Copyright © 2005-2010 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Data @@ -51,6 +51,7 @@ class TDbTransaction extends TComponent */ public function __construct(TDbConnection $connection) { + parent::__construct(); $this->_connection=$connection; $this->setActive(true); } diff --git a/framework/Exceptions/TErrorHandler.php b/framework/Exceptions/TErrorHandler.php index 4ac312d0..f4db5050 100644 --- a/framework/Exceptions/TErrorHandler.php +++ b/framework/Exceptions/TErrorHandler.php @@ -1,404 +1,404 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2008 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Exceptions - */ - -/** - * TErrorHandler class - * - * TErrorHandler handles all PHP user errors and exceptions generated during - * servicing user requests. It displays these errors using different templates - * and if possible, using languages preferred by the client user. - * Note, PHP parsing errors cannot be caught and handled by TErrorHandler. - * - * The templates used to format the error output are stored under System.Exceptions. - * You may choose to use your own templates, should you not like the templates - * provided by Prado. Simply set {@link setErrorTemplatePath ErrorTemplatePath} - * to the path (in namespace format) storing your own templates. - * - * There are two sets of templates, one for errors to be displayed to client users - * (called external errors), one for errors to be displayed to system developers - * (called internal errors). The template file name for the former is - * error[StatusCode][-LanguageCode].html, and for the latter it is - * exception[-LanguageCode].html, where StatusCode refers to response status - * code (e.g. 404, 500) specified when {@link THttpException} is thrown, - * and LanguageCode is the client user preferred language code (e.g. en, zh, de). - * The templates error.html and exception.html are default ones - * that are used if no other appropriate templates are available. - * Note, these templates are not Prado control templates. They are simply - * html files with keywords (e.g. %%ErrorMessage%%, %%Version%%) - * to be replaced with the corresponding information. - * - * By default, TErrorHandler is registered with {@link TApplication} as the - * error handler module. It can be accessed via {@link TApplication::getErrorHandler()}. - * You seldom need to deal with the error handler directly. It is mainly used - * by the application object to handle errors. - * - * TErrorHandler may be configured in application configuration file as follows - * - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TErrorHandler extends TModule -{ - /** - * error template file basename - */ - const ERROR_FILE_NAME='error'; - /** - * exception template file basename - */ - const EXCEPTION_FILE_NAME='exception'; - /** - * number of lines before and after the error line to be displayed in case of an exception - */ - const SOURCE_LINES=12; - - /** - * @var string error template directory - */ - private $_templatePath=null; - - /** - * Initializes the module. - * This method is required by IModule and is invoked by application. - * @param TXmlElement module configuration - */ - public function init($config) - { - $this->getApplication()->setErrorHandler($this); - } - - /** - * @return string the directory containing error template files. - */ - public function getErrorTemplatePath() + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Exceptions + */ + +/** + * TErrorHandler class + * + * TErrorHandler handles all PHP user errors and exceptions generated during + * servicing user requests. It displays these errors using different templates + * and if possible, using languages preferred by the client user. + * Note, PHP parsing errors cannot be caught and handled by TErrorHandler. + * + * The templates used to format the error output are stored under System.Exceptions. + * You may choose to use your own templates, should you not like the templates + * provided by Prado. Simply set {@link setErrorTemplatePath ErrorTemplatePath} + * to the path (in namespace format) storing your own templates. + * + * There are two sets of templates, one for errors to be displayed to client users + * (called external errors), one for errors to be displayed to system developers + * (called internal errors). The template file name for the former is + * error[StatusCode][-LanguageCode].html, and for the latter it is + * exception[-LanguageCode].html, where StatusCode refers to response status + * code (e.g. 404, 500) specified when {@link THttpException} is thrown, + * and LanguageCode is the client user preferred language code (e.g. en, zh, de). + * The templates error.html and exception.html are default ones + * that are used if no other appropriate templates are available. + * Note, these templates are not Prado control templates. They are simply + * html files with keywords (e.g. %%ErrorMessage%%, %%Version%%) + * to be replaced with the corresponding information. + * + * By default, TErrorHandler is registered with {@link TApplication} as the + * error handler module. It can be accessed via {@link TApplication::getErrorHandler()}. + * You seldom need to deal with the error handler directly. It is mainly used + * by the application object to handle errors. + * + * TErrorHandler may be configured in application configuration file as follows + * + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TErrorHandler extends TModule +{ + /** + * error template file basename + */ + const ERROR_FILE_NAME='error'; + /** + * exception template file basename + */ + const EXCEPTION_FILE_NAME='exception'; + /** + * number of lines before and after the error line to be displayed in case of an exception + */ + const SOURCE_LINES=12; + + /** + * @var string error template directory + */ + private $_templatePath=null; + + /** + * Initializes the module. + * This method is required by IModule and is invoked by application. + * @param TXmlElement module configuration + */ + public function init($config) + { + $this->getApplication()->setErrorHandler($this); + } + + /** + * @return string the directory containing error template files. + */ + public function getErrorTemplatePath() { if($this->_templatePath===null) - $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates'; - return $this->_templatePath; - } - - /** - * Sets the path storing all error and exception template files. - * The path must be in namespace format, such as System.Exceptions (which is the default). - * @param string template path in namespace format - * @throws TConfigurationException if the template path is invalid - */ - public function setErrorTemplatePath($value) - { - if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath)) - $this->_templatePath=$templatePath; - else - throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value); - } - - /** - * Handles PHP user errors and exceptions. - * This is the event handler responding to the Error event - * raised in {@link TApplication}. - * The method mainly uses appropriate template to display the error/exception. - * It terminates the application immediately after the error is displayed. - * @param mixed sender of the event - * @param mixed event parameter (if the event is raised by TApplication, it refers to the exception instance) - */ - public function handleError($sender,$param) - { - static $handling=false; - // We need to restore error and exception handlers, - // because within error and exception handlers, new errors and exceptions - // cannot be handled properly by PHP - restore_error_handler(); - restore_exception_handler(); - // ensure that we do not enter infinite loop of error handling - 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); - } - } - - - /** - * @param string $value - * @param Exception|null$exception - * @return string - * @since 3.1.6 - */ - protected static function hideSecurityRelated($value, $exception=null) - { - $aRpl = array(); - if($exception !== null && $exception instanceof Exception) - { - $aTrace = $exception->getTrace(); - foreach($aTrace as $item) - { - $file = $item['file']; - $aRpl[dirname($file) . DIRECTORY_SEPARATOR] = '' . DIRECTORY_SEPARATOR; - } - } - $aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}'; - $aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}'; - $aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR; - if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]); - $aRpl = array_reverse($aRpl, true); - - return str_replace(array_keys($aRpl), $aRpl, $value); - } - - /** - * Displays error to the client user. - * THttpException and errors happened when the application is in Debug - * mode will be displayed to the client user. - * @param integer response status code - * @param Exception exception instance - */ - 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']:''; - - $isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug; - - $errorMessage = $exception->getMessage(); - if($isDebug) - $version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion(); - else - { - $version=''; - $errorMessage = self::hideSecurityRelated($errorMessage, $exception); - } - $tokens=array( - '%%StatusCode%%' => "$statusCode", - '%%ErrorMessage%%' => htmlspecialchars($errorMessage), - '%%ServerAdmin%%' => $serverAdmin, - '%%Version%%' => $version, - '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) - ); - - if($isDebug) - header("HTTP/1.0 $statusCode ".$exception->getMessage(), true, $statusCode); - else - header("HTTP/1.0 $statusCode", true, $statusCode); - - echo strtr($content,$tokens); - } - - /** - * Handles error occurs during error handling (called recursive error). - * THttpException and errors happened when the application is in Debug - * mode will be displayed to the client user. - * Error is displayed without using existing template to prevent further errors. - * @param Exception exception instance - */ - protected function handleRecursiveError($exception) - { - if($this->getApplication()->getMode()===TApplicationMode::Debug) - { - echo "Recursive Error\n"; - echo "

Recursive Error

\n"; - echo "
".$exception->__toString()."
\n"; - echo ""; - } - else - { - error_log("Error happened while processing an existing error:\n".$exception->__toString()); - header('HTTP/1.0 500 Internal Error'); - } - } - - /** - * Displays exception information. - * Exceptions are displayed with rich context information, including - * the call stack and the context source code. - * This method is only invoked when application is in Debug mode. - * @param Exception exception instance - */ - 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'].' PRADO/'.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); - } - - /** - * Retrieves the template used for displaying internal exceptions. - * Internal exceptions will be displayed with source code causing the exception. - * This occurs when the application is in debug mode. - * @param Exception the exception to be displayed - * @return string the template content - */ - 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; - } - - /** - * Retrieves the template used for displaying external exceptions. - * External exceptions are those displayed to end-users. They do not contain - * error source code. Therefore, you might want to override this method - * to provide your own error template for displaying certain external exceptions. - * The following tokens in the template will be replaced with corresponding content: - * %%StatusCode%% : the status code of the exception - * %%ErrorMessage%% : the error message (HTML encoded). - * %%ServerAdmin%% : the server admin information (retrieved from Web server configuration) - * %%Version%% : the version information of the Web server. - * %%Time%% : the time the exception occurs at - * - * @param integer status code (such as 404, 500, etc.) - * @param Exception the exception to be displayed - * @return string the template 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 PHP exception, we want to show the 2nd stack level context - // because the 1st stack level is of little use (it's in error handler) - if($exception instanceof TPhpErrorException) - $result=isset($trace[0]['file'])?$trace[0]:$trace[1]; - else if($exception instanceof TInvalidOperationException) - { - // in case of getter or setter error, find out the exact file and row - 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.="
".$line."
"; - } - 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/',"\${1}",$message); - } -} - + $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates'; + return $this->_templatePath; + } + + /** + * Sets the path storing all error and exception template files. + * The path must be in namespace format, such as System.Exceptions (which is the default). + * @param string template path in namespace format + * @throws TConfigurationException if the template path is invalid + */ + public function setErrorTemplatePath($value) + { + if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath)) + $this->_templatePath=$templatePath; + else + throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value); + } + + /** + * Handles PHP user errors and exceptions. + * This is the event handler responding to the Error event + * raised in {@link TApplication}. + * The method mainly uses appropriate template to display the error/exception. + * It terminates the application immediately after the error is displayed. + * @param mixed sender of the event + * @param mixed event parameter (if the event is raised by TApplication, it refers to the exception instance) + */ + public function handleError($sender,$param) + { + static $handling=false; + // We need to restore error and exception handlers, + // because within error and exception handlers, new errors and exceptions + // cannot be handled properly by PHP + restore_error_handler(); + restore_exception_handler(); + // ensure that we do not enter infinite loop of error handling + 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); + } + } + + + /** + * @param string $value + * @param Exception|null$exception + * @return string + * @since 3.1.6 + */ + protected static function hideSecurityRelated($value, $exception=null) + { + $aRpl = array(); + if($exception !== null && $exception instanceof Exception) + { + $aTrace = $exception->getTrace(); + foreach($aTrace as $item) + { + $file = $item['file']; + $aRpl[dirname($file) . DIRECTORY_SEPARATOR] = '' . DIRECTORY_SEPARATOR; + } + } + $aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}'; + $aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}'; + $aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR; + if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]); + $aRpl = array_reverse($aRpl, true); + + return str_replace(array_keys($aRpl), $aRpl, $value); + } + + /** + * Displays error to the client user. + * THttpException and errors happened when the application is in Debug + * mode will be displayed to the client user. + * @param integer response status code + * @param Exception exception instance + */ + 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']:''; + + $isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug; + + $errorMessage = $exception->getMessage(); + if($isDebug) + $version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion(); + else + { + $version=''; + $errorMessage = self::hideSecurityRelated($errorMessage, $exception); + } + $tokens=array( + '%%StatusCode%%' => "$statusCode", + '%%ErrorMessage%%' => htmlspecialchars($errorMessage), + '%%ServerAdmin%%' => $serverAdmin, + '%%Version%%' => $version, + '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) + ); + + if($isDebug) + header("HTTP/1.0 $statusCode ".$exception->getMessage(), true, TPropertyValue::ensureInteger($statusCode)); + else + header("HTTP/1.0 $statusCode", true, TPropertyValue::ensureInteger($statusCode)); + + echo strtr($content,$tokens); + } + + /** + * Handles error occurs during error handling (called recursive error). + * THttpException and errors happened when the application is in Debug + * mode will be displayed to the client user. + * Error is displayed without using existing template to prevent further errors. + * @param Exception exception instance + */ + protected function handleRecursiveError($exception) + { + if($this->getApplication()->getMode()===TApplicationMode::Debug) + { + echo "Recursive Error\n"; + echo "

Recursive Error

\n"; + echo "
".$exception->__toString()."
\n"; + echo ""; + } + else + { + error_log("Error happened while processing an existing error:\n".$exception->__toString()); + header('HTTP/1.0 500 Internal Error'); + } + } + + /** + * Displays exception information. + * Exceptions are displayed with rich context information, including + * the call stack and the context source code. + * This method is only invoked when application is in Debug mode. + * @param Exception exception instance + */ + 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'].' PRADO/'.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); + } + + /** + * Retrieves the template used for displaying internal exceptions. + * Internal exceptions will be displayed with source code causing the exception. + * This occurs when the application is in debug mode. + * @param Exception the exception to be displayed + * @return string the template content + */ + 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; + } + + /** + * Retrieves the template used for displaying external exceptions. + * External exceptions are those displayed to end-users. They do not contain + * error source code. Therefore, you might want to override this method + * to provide your own error template for displaying certain external exceptions. + * The following tokens in the template will be replaced with corresponding content: + * %%StatusCode%% : the status code of the exception + * %%ErrorMessage%% : the error message (HTML encoded). + * %%ServerAdmin%% : the server admin information (retrieved from Web server configuration) + * %%Version%% : the version information of the Web server. + * %%Time%% : the time the exception occurs at + * + * @param integer status code (such as 404, 500, etc.) + * @param Exception the exception to be displayed + * @return string the template 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 PHP exception, we want to show the 2nd stack level context + // because the 1st stack level is of little use (it's in error handler) + if($exception instanceof TPhpErrorException) + $result=isset($trace[0]['file'])?$trace[0]:$trace[1]; + else if($exception instanceof TInvalidOperationException) + { + // in case of getter or setter error, find out the exact file and row + 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.="
".$line."
"; + } + 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/',"\${1}",$message); + } +} + diff --git a/framework/Exceptions/messages/messages-fr.txt b/framework/Exceptions/messages/messages-fr.txt index 5dce3812..4e6a396b 100644 --- a/framework/Exceptions/messages/messages-fr.txt +++ b/framework/Exceptions/messages/messages-fr.txt @@ -366,6 +366,7 @@ tactivecustomvalidator_clientfunction_unsupported = {0} does not support client dbconnection_open_failed = TDbConnection failed to establish DB connection: {0} dbconnection_connection_inactive = TDbConnection is inactive. +dbconnection_unsupported_driver_charset = Le pilote de base de données '{0}' ne supporte pas la modification du jeu de caractères. dbcommand_prepare_failed = TDbCommand failed to prepare the SQL statement "{1}": {0} dbcommand_execute_failed = TDbCommand failed to execute the SQL statement "{1}": {0} @@ -409,3 +410,9 @@ feedservice_id_required = TFeedService requires 'id' attribute in its feed e feedservice_feedtype_invalid = The class feed '{0}' must implement IFeedContentProvider interface. feedservice_class_required = TFeedService requires 'class' attribute in its feed elements. feedservice_feed_unknown = Unknown feed '{0}' requested. + +tactivetablecell_control_outoftable = {0} '{1}' must be enclosed within a TTableRow control. +tactivetablecell_control_notincollection = {0} '{1}' no member of the TTableCellCollection of the parent TTableRow control. + +tactivetablerow_control_outoftable = {0} '{1}' must be enclosed within a TTable control. +tactivetablerow_control_notincollection = {0} '{1}' no member of the TTableRowCollection of the parent TTable control. \ No newline at end of file diff --git a/framework/Exceptions/messages/messages-id.txt b/framework/Exceptions/messages/messages-id.txt index 61699ddd..687d4f30 100644 --- a/framework/Exceptions/messages/messages-id.txt +++ b/framework/Exceptions/messages/messages-id.txt @@ -367,6 +367,7 @@ tactivecustomvalidator_clientfunction_unsupported = {0} tidak mendukung fungsi v dbconnection_open_failed = TDbConnection gagal untuk menyelesaikan koneksi DB: {0} dbconnection_connection_inactive = TDbConnection tidak aktif. +dbconnection_unsupported_driver_charset = Database driver '{0}' doesn't support setting charset. dbcommand_prepare_failed = TDbCommand gagal untuk menyiapkan pernyataan SQL "{1}": {0} dbcommand_execute_failed = TDbCommand gagal untuk menjalankan pernyataan SQL "{1}": {0} diff --git a/framework/Exceptions/messages/messages-zh.txt b/framework/Exceptions/messages/messages-zh.txt index 1859aa92..9dc14a8b 100644 --- a/framework/Exceptions/messages/messages-zh.txt +++ b/framework/Exceptions/messages/messages-zh.txt @@ -372,6 +372,7 @@ tactivecustomvalidator_clientfunction_unsupported = {0} does not support client dbconnection_open_failed = TDbConnection failed to establish DB connection: {0} dbconnection_connection_inactive = TDbConnection is inactive. +dbconnection_unsupported_driver_charset = Database driver '{0}' doesn't support setting charset. dbcommand_prepare_failed = TDbCommand failed to prepare the SQL statement "{1}": {0} dbcommand_execute_failed = TDbCommand failed to execute the SQL statement "{1}": {0} diff --git a/framework/Exceptions/messages/messages.txt b/framework/Exceptions/messages/messages.txt index 0750c38d..fd85920c 100644 --- a/framework/Exceptions/messages/messages.txt +++ b/framework/Exceptions/messages/messages.txt @@ -24,7 +24,7 @@ map_item_unremovable = The item cannot be removed from the map. map_data_not_iterable = Data must be either an array or an object implementing Traversable interface. map_readonly = {0} is read-only. -application_includefile_invalid = Unable to find application configuration {0}. Make sure it is in namespace format and the file ends with ".xml". +application_includefile_invalid = Unable to find application configuration {0}. Make sure it is in namespace format and the file ends with ".xml" or ".php". application_basepath_invalid = Application base path '{0}' does not exist or is not a directory. application_runtimepath_invalid = Application runtime path '{0}' does not exist or is not writable by Web server process. application_service_invalid = Service '{0}' must implement IService interface. @@ -115,7 +115,7 @@ pageservice_page_required = Page Name Required pageservice_defaultpage_unchangeable = TPageService.DefaultPage cannot be modified after the service is initialized. pageservice_basepath_unchangeable = TPageService.BasePath cannot be modified after the service is initialized. pageservice_pageclass_invalid = Page class {0} is invalid. It should be TPage or extend from TPage. -pageservice_includefile_invalid = Unable to find page service configuration {0}. Make sure it is in namespace format and the file ends with ".xml". +pageservice_includefile_invalid = Unable to find page service configuration {0}. Make sure it is in namespace format and the file ends with ".xml" or ".php". pageserviceconf_file_invalid = Unable to open page directory configuration file '{0}'. pageserviceconf_aliaspath_invalid = uses an invalid file path "{1}" in page directory configuration file '{2}'. @@ -317,7 +317,7 @@ htmlarea_textmode_readonly = THtmlArea.TextMode is read-only. htmlarea_tarfile_invalid = THtmlArea is unable to locate the TinyMCE tar file. parametermodule_parameterfile_unchangeable = TParameterModule.ParameterFile is not changeable because the module is already initialized. -parametermodule_parameterfile_invalid = TParameterModule.ParameterFile '{0}' is invalid. Make sure it is in namespace format and the file extension is '.xml'. +parametermodule_parameterfile_invalid = TParameterModule.ParameterFile '{0}' is invalid. Make sure it is in namespace format and the file extension is '.xml' or '.php'. parametermodule_parameterid_required = Parameter element must have 'id' attribute. datagridcolumn_id_invalid = {0}.ID '{1}' is invalid. Only alphanumeric and underline characters are allowed. The first character must be an alphabetic or underline character. @@ -376,6 +376,7 @@ tactivecustomvalidator_clientfunction_unsupported = {0} does not support client dbconnection_open_failed = TDbConnection failed to establish DB connection: {0} dbconnection_connection_inactive = TDbConnection is inactive. +dbconnection_unsupported_driver_charset = Database driver '{0}' doesn't support setting charset. dbcommand_prepare_failed = TDbCommand failed to prepare the SQL statement "{1}": {0} dbcommand_execute_failed = TDbCommand failed to execute the SQL statement "{1}": {0} @@ -403,7 +404,7 @@ dbtablegateway_invalid_table_info = Table must be a string or an instance of TD directorycachedependency_directory_invalid = TDirectoryCacheDependency.Directory {0} does not refer to a valid directory. cachedependencylist_cachedependency_required = Only objects implementing ICacheDependency can be added into TCacheDependencyList. -soapservice_configfile_invalid = TSoapService.ConfigFile '{0}' does not exist. Note, it has to be specified in a namespace format and the file extension must be '.xml'. +soapservice_configfile_invalid = TSoapService.ConfigFile '{0}' does not exist. Note, it has to be specified in a namespace format and the file extension must be '.xml' or '.php'. soapservice_request_invalid = SOAP server '{0}' not found. soapservice_serverid_required = element must have 'id' attribute. soapservice_serverid_duplicated = SOAP server ID '{0}' is duplicated. @@ -470,8 +471,18 @@ ar_save_invalid = The {0} instance cannot be saved because it is either de ar_delete_invalid = The {0} instance cannot be deleted because it is either a new record or a record already deleted. datasource_dbconnection_invalid = TDataSourceConfig.DbConnection '{0}' is invalid. Please make sure it points to a valid application module. +distributeddatasource_child_required = {0} requires one '{1}' child element at minimum. +masterslavedbconnection_connection_exists = {0}.{1} connection already exists. +masterslavedbconnection_interface_required = {0}.{1} requires an instance implementing {2} interface. +slavedbconnection_requires_master = {0} requires a {1}. response_status_reason_missing = HTTP 1.1 need reason for extended status-codes response_status_reason_badchars = For HTTP 1.1 header, the token status-reason must not contain token CR or LF activefileupload_temppath_invalid = TActiveFileUpload TempPath path '{0}' does not exist or is not writable by Web server process. + +tactivetablecell_control_outoftable = {0} '{1}' must be enclosed within a TTableRow control. +tactivetablecell_control_notincollection = {0} '{1}' no member of the TTableCellCollection of the parent TTableRow control. + +tactivetablerow_control_outoftable = {0} '{1}' must be enclosed within a TTable control. +tactivetablerow_control_notincollection = {0} '{1}' no member of the TTableRowCollection of the parent TTable control. \ No newline at end of file -- cgit v1.2.3