Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/*** TActiveRecordGateway, TActiveRecordStatementType, TActiveRecordEventParameter classes file.** @author Wei Zhuo <weizhuo[at]gmail[dot]com>* @link http://www.pradosoft.com/* @copyright Copyright © 2005-2008 PradoSoft* @license http://www.pradosoft.com/license/* @version $Id: TActiveRecordGateway.php 2541 2008-10-21 15:05:13Z qiang.xue $* @package System.Data.ActiveRecord*//*** TActiveRecordGateway excutes the SQL command queries and returns the data* record as arrays (for most finder methods).** @author Wei Zhuo <weizho[at]gmail[dot]com>* @version $Id: TActiveRecordGateway.php 2541 2008-10-21 15:05:13Z qiang.xue $* @package System.Data.ActiveRecord* @since 3.1*/class TActiveRecordGateway extends TComponent{private $_manager;private $_tables=array(); //table cacheprivate $_meta=array(); //meta data cache.private $_commandBuilders=array();private $_currentRecord;/*** Constant name for specifying optional table name in TActiveRecord.*/const TABLE_CONST='TABLE';/*** Method name for returning optional table name in in TActiveRecord*/const TABLE_METHOD='table';/*** Record gateway constructor.* @param TActiveRecordManager $manager*/public function __construct(TActiveRecordManager $manager){$this->_manager=$manager;}/*** @return TActiveRecordManager record manager.*/protected function getManager(){return $this->_manager;}/*** Gets the table name from the 'TABLE' constant of the active record* class if defined, otherwise use the class name as table name.* @param TActiveRecord active record instance* @return string table name for the given record class.*/protected function getRecordTableName(TActiveRecord $record){$class = new ReflectionClass($record);if($class->hasConstant(self::TABLE_CONST)){$value = $class->getConstant(self::TABLE_CONST);if(empty($value))throw new TActiveRecordException('ar_invalid_tablename_property',get_class($record),self::TABLE_CONST);return $value;}elseif ($class->hasMethod(self::TABLE_METHOD)){$value = $record->{self::TABLE_METHOD}();if(empty($value))throw new TActiveRecordException('ar_invalid_tablename_method',get_class($record),self::TABLE_METHOD);return $value;}elsereturn strtolower(get_class($record));}/*** Returns table information, trys the application cache first.* @param TActiveRecord $record* @return TDbTableInfo table information.*/public function getRecordTableInfo(TActiveRecord $record){$tableName = $this->getRecordTableName($record);return $this->getTableInfo($record->getDbConnection(), $tableName);}/*** Returns table information for table in the database connection.* @param TDbConnection database connection* @param string table name* @return TDbTableInfo table details.*/public function getTableInfo(TDbConnection $connection, $tableName){$connStr = $connection->getConnectionString();$key = $connStr.$tableName;if(!isset($this->_tables[$key])){//call this first to ensure that unserializing the cache//will find the correct driver dependent classes.if(!isset($this->_meta[$connStr])){Prado::using('System.Data.Common.TDbMetaData');$this->_meta[$connStr] = TDbMetaData::getInstance($connection);}$tableInfo = null;if(($cache=$this->getManager()->getCache())!==null)$tableInfo = $cache->get($key);if(empty($tableInfo)){$tableInfo = $this->_meta[$connStr]->getTableInfo($tableName);if($cache!==null)$cache->set($key, $tableInfo);}$this->_tables[$key] = $tableInfo;}return $this->_tables[$key];}/*** @param TActiveRecord $record* @return TDataGatewayCommand*/public function getCommand(TActiveRecord $record){$conn = $record->getDbConnection();$connStr = $conn->getConnectionString();$tableInfo = $this->getRecordTableInfo($record);if(!isset($this->_commandBuilders[$connStr])){$builder = $tableInfo->createCommandBuilder($record->getDbConnection());Prado::using('System.Data.DataGateway.TDataGatewayCommand');$command = new TDataGatewayCommand($builder);$command->OnCreateCommand[] = array($this, 'onCreateCommand');$command->OnExecuteCommand[] = array($this, 'onExecuteCommand');$this->_commandBuilders[$connStr] = $command;}$this->_commandBuilders[$connStr]->getBuilder()->setTableInfo($tableInfo);$this->_currentRecord=$record;return $this->_commandBuilders[$connStr];}/*** Raised when a command is prepared and parameter binding is completed.* The parameter object is TDataGatewayEventParameter of which the* {@link TDataGatewayEventParameter::getCommand Command} property can be* inspected to obtain the sql query to be executed.* This method also raises the OnCreateCommand event on the ActiveRecord* object calling this gateway.* @param TDataGatewayCommand originator $sender* @param TDataGatewayEventParameter*/public function onCreateCommand($sender, $param){$this->raiseEvent('OnCreateCommand', $this, $param);if($this->_currentRecord!==null)$this->_currentRecord->onCreateCommand($param);}/*** Raised when a command is executed and the result from the database was returned.* The parameter object is TDataGatewayResultEventParameter of which the* {@link TDataGatewayEventParameter::getResult Result} property contains* the data return from the database. The data returned can be changed* by setting the {@link TDataGatewayEventParameter::setResult Result} property.* This method also raises the OnCreateCommand event on the ActiveRecord* object calling this gateway.* @param TDataGatewayCommand originator $sender* @param TDataGatewayResultEventParameter*/public function onExecuteCommand($sender, $param){$this->raiseEvent('OnExecuteCommand', $this, $param);if($this->_currentRecord!==null)$this->_currentRecord->onExecuteCommand($param);}/*** Returns record data matching the given primary key(s). If the table uses* composite key, specify the name value pairs as an array.* @param TActiveRecord active record instance.* @param array primary name value pairs* @return array record data*/public function findRecordByPK(TActiveRecord $record,$keys){$command = $this->getCommand($record);return $command->findByPk($keys);}/*** Returns records matching the list of given primary keys.* @param TActiveRecord active record instance.* @param array list of primary name value pairs* @return array matching data.*/public function findRecordsByPks(TActiveRecord $record, $keys){return $this->getCommand($record)->findAllByPk($keys);}/*** Returns record data matching the given critera. If $iterator is true, it will* return multiple rows as TDbDataReader otherwise it returns the <b>first</b> row data.* @param TActiveRecord active record finder instance.* @param TActiveRecordCriteria search criteria.* @param boolean true to return multiple rows as iterator, false returns first row.* @return mixed matching data.*/public function findRecordsByCriteria(TActiveRecord $record, $criteria, $iterator=false){$command = $this->getCommand($record);return $iterator ? $command->findAll($criteria) : $command->find($criteria);}/*** Return record data from sql query.* @param TActiveRecord active record finder instance.* @param TActiveRecordCriteria sql query* @return array result.*/public function findRecordBySql(TActiveRecord $record, $criteria){return $this->getCommand($record)->findBySql($criteria);}/*** Return record data from sql query.* @param TActiveRecord active record finder instance.* @param TActiveRecordCriteria sql query* @return TDbDataReader result iterator.*/public function findRecordsBySql(TActiveRecord $record, $criteria){return $this->getCommand($record)->findAllBySql($criteria);}public function findRecordsByIndex(TActiveRecord $record, $criteria, $fields, $values){return $this->getCommand($record)->findAllByIndex($criteria,$fields,$values);}/*** Returns the number of records that match the given criteria.* @param TActiveRecord active record finder instance.* @param TActiveRecordCriteria search criteria* @return int number of records.*/public function countRecords(TActiveRecord $record, $criteria){return $this->getCommand($record)->count($criteria);}/*** Insert a new record.* @param TActiveRecord new record.* @return int number of rows affected.*/public function insert(TActiveRecord $record){//$this->updateAssociatedRecords($record,true);$result = $this->getCommand($record)->insert($this->getInsertValues($record));if($result)$this->updatePostInsert($record);//$this->updateAssociatedRecords($record);return $result;}/*** Sets the last insert ID to the corresponding property of the record if available.* @param TActiveRecord record for insertion*/protected function updatePostInsert($record){$command = $this->getCommand($record);$tableInfo = $command->getTableInfo();foreach($tableInfo->getColumns() as $name => $column){if($column->hasSequence())$record->setColumnValue($name,$command->getLastInsertID($column->getSequenceName()));}}/*** @param TActiveRecord record* @return array insert values.*/protected function getInsertValues(TActiveRecord $record){$values=array();$tableInfo = $this->getCommand($record)->getTableInfo();foreach($tableInfo->getColumns() as $name=>$column){if($column->getIsExcluded())continue;$value = $record->getColumnValue($name);if(!$column->getAllowNull() && $value===null && !$column->hasSequence() && !$column->getDefaultValue()){throw new TActiveRecordException('ar_value_must_not_be_null', get_class($record),$tableInfo->getTableFullName(), $name);}if($value!==null)$values[$name] = $value;}return $values;}/*** Update the record.* @param TActiveRecord dirty record.* @return int number of rows affected.*/public function update(TActiveRecord $record){//$this->updateAssociatedRecords($record,true);list($data, $keys) = $this->getUpdateValues($record);$result = $this->getCommand($record)->updateByPk($data, $keys);//$this->updateAssociatedRecords($record);return $result;}protected function getUpdateValues(TActiveRecord $record){$values=array();$tableInfo = $this->getCommand($record)->getTableInfo();$primary=array();foreach($tableInfo->getColumns() as $name=>$column){if($column->getIsExcluded())continue;$value = $record->getColumnValue($name);if(!$column->getAllowNull() && $value===null){throw new TActiveRecordException('ar_value_must_not_be_null', get_class($record),$tableInfo->getTableFullName(), $name);}if($column->getIsPrimaryKey())$primary[] = $value;else$values[$name] = $value;}return array($values,$primary);}protected function updateAssociatedRecords(TActiveRecord $record,$updateBelongsTo=false){$context = new TActiveRecordRelationContext($record);return $context->updateAssociatedRecords($updateBelongsTo);}/*** Delete the record.* @param TActiveRecord record to be deleted.* @return int number of rows affected.*/public function delete(TActiveRecord $record){return $this->getCommand($record)->deleteByPk($this->getPrimaryKeyValues($record));}protected function getPrimaryKeyValues(TActiveRecord $record){$tableInfo = $this->getCommand($record)->getTableInfo();$primary=array();foreach($tableInfo->getColumns() as $name=>$column){if($column->getIsPrimaryKey())$primary[$name] = $record->getColumnValue($name);}return $primary;}/*** Delete multiple records using primary keys.* @param TActiveRecord finder instance.* @return int number of rows deleted.*/public function deleteRecordsByPk(TActiveRecord $record, $keys){return $this->getCommand($record)->deleteByPk($keys);}/*** Delete multiple records by criteria.* @param TActiveRecord active record finder instance.* @param TActiveRecordCriteria search criteria* @return int number of records.*/public function deleteRecordsByCriteria(TActiveRecord $record, $criteria){return $this->getCommand($record)->delete($criteria);}/*** Raise the corresponding command event, insert, update, delete or select.* @param string command type* @param TDbCommand sql command to be executed.* @param TActiveRecord active record* @param TActiveRecordCriteria data for the command.*/protected function raiseCommandEvent($event,$command,$record,$criteria){if(!($criteria instanceof TSqlCriteria))$criteria = new TActiveRecordCriteria(null,$criteria);$param = new TActiveRecordEventParameter($command,$record,$criteria);$manager = $record->getRecordManager();$manager->{$event}($param);$record->{$event}($param);}}