Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/*** TMappedStatement and related classes.** @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: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $* @package System.Data.SqlMap.Statements*//*** TMappedStatement class executes SQL mapped statements. Mapped Statements can* hold any SQL statement and use Parameter Maps and Result Maps for input and output.** This class is usualy instantiated during SQLMap configuration by TSqlDomBuilder.** @author Wei Zhuo <weizhuo[at]gmail[dot]com>* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $* @package System.Data.SqlMap.Statements* @since 3.0*/class TMappedStatement extends TComponent implements IMappedStatement{/*** @var TSqlMapStatement current SQL statement.*/private $_statement;/*** @var TPreparedCommand SQL command prepareer*/private $_command;/*** @var TSqlMapper sqlmap used by this mapper.*/private $_manager;/*** @var TPostSelectBinding[] post select statement queue.*/private $_selectQueque=array();/*** @var boolean true when data is mapped to a particular row.*/private $_IsRowDataFound = false;/*** @var TSQLMapObjectCollectionTree group by object collection tree*/private $_groupBy;/*** @var Post select is to query for list.*/const QUERY_FOR_LIST = 0;/*** @var Post select is to query for list.*/const QUERY_FOR_ARRAY = 1;/*** @var Post select is to query for object.*/const QUERY_FOR_OBJECT = 2;/*** @return string Name used to identify the TMappedStatement amongst the others.* This the name of the SQL statement by default.*/public function getID(){return $this->_statement->ID;}/*** @return TSqlMapStatement The SQL statment used by this MappedStatement*/public function getStatement(){return $this->_statement;}/*** @return TSqlMapper The SqlMap used by this MappedStatement*/public function getManager(){return $this->_manager;}/*** @return TPreparedCommand command to prepare SQL statements.*/public function getCommand(){return $this->_command;}/*** Empty the group by results cache.*/protected function initialGroupByResults(){$this->_groupBy = new TSqlMapObjectCollectionTree();}/*** Creates a new mapped statement.* @param TSqlMapper an sqlmap.* @param TSqlMapStatement An SQL statement.*/public function __construct(TSqlMapManager $sqlMap, TSqlMapStatement $statement){$this->_manager = $sqlMap;$this->_statement = $statement;$this->_command = new TPreparedCommand();$this->initialGroupByResults();}public function getSqlString(){return $this->getStatement()->getSqlText()->getPreparedStatement()->getPreparedSql();}/*** Execute SQL Query.* @param IDbConnection database connection* @param array SQL statement and parameters.* @return mixed record set if applicable.* @throws TSqlMapExecutionException if execution error or false record set.* @throws TSqlMapQueryExecutionException if any execution error*//* protected function executeSQLQuery($connection, $sql){try{if(!($recordSet = $connection->execute($sql['sql'],$sql['parameters']))){throw new TSqlMapExecutionException('sqlmap_execution_error_no_record', $this->getID(),$connection->ErrorMsg());}return $recordSet;}catch (Exception $e){throw new TSqlMapQueryExecutionException($this->getStatement(), $e);}}*//*** Execute SQL Query with limits.* @param IDbConnection database connection* @param array SQL statement and parameters.* @return mixed record set if applicable.* @throws TSqlMapExecutionException if execution error or false record set.* @throws TSqlMapQueryExecutionException if any execution error*/protected function executeSQLQueryLimit($connection, $command, $max, $skip){if($max>-1 || $skip > -1){$maxStr=$max>0?' LIMIT '.$max:'';$skipStr=$skip>0?' OFFSET '.$skip:'';$command->setText($command->getText().$maxStr.$skipStr);}$connection->setActive(true);return $command->query();/*//var_dump($command);try{$recordSet = $connection->selectLimit($sql['sql'],$max,$skip,$sql['parameters']);if(!$recordSet){throw new TSqlMapExecutionException('sqlmap_execution_error_query_for_list',$connection->ErrorMsg());}return $recordSet;}catch (Exception $e){throw new TSqlMapQueryExecutionException($this->getStatement(), $e);}*/}/*** Executes the SQL and retuns a List of result objects.* @param IDbConnection database connection* @param mixed The object used to set the parameters in the SQL.* @param object result collection object.* @param integer The number of rows to skip over.* @param integer The maximum number of rows to return.* @return array a list of result objects* @param callback row delegate handler* @see executeQueryForList()*/public function executeQueryForList($connection, $parameter, $result=null, $skip=-1, $max=-1, $delegate=null){$sql = $this->_command->create($this->_manager, $connection, $this->_statement, $parameter,$skip,$max);return $this->runQueryForList($connection, $parameter, $sql, $result, $delegate);}/*** Executes the SQL and retuns a List of result objects.** This method should only be called by internal developers, consider using* <tt>executeQueryForList()</tt> first.** @param IDbConnection database connection* @param mixed The object used to set the parameters in the SQL.* @param array SQL string and subsititution parameters.* @param object result collection object.* @param integer The number of rows to skip over.* @param integer The maximum number of rows to return.* @param callback row delegate handler* @return array a list of result objects* @see executeQueryForList()*/public function runQueryForList($connection, $parameter, $sql, $result, $delegate=null){$registry=$this->getManager()->getTypeHandlers();$list = $result instanceof ArrayAccess ? $result :$this->_statement->createInstanceOfListClass($registry);$connection->setActive(true);$reader = $sql->query();//$reader = $this->executeSQLQueryLimit($connection, $sql, $max, $skip);if(!is_null($delegate)){foreach($reader as $row){$obj = $this->applyResultMap($row);$param = new TResultSetListItemParameter($obj, $parameter, $list);$this->raiseRowDelegate($delegate, $param);}}else{//var_dump($sql,$parameter);foreach($reader as $row){// var_dump($row);$list[] = $this->applyResultMap($row);}}if(!$this->_groupBy->isEmpty()){$list = $this->_groupBy->collect();$this->initialGroupByResults();}$this->executePostSelect($connection);$this->onExecuteQuery($sql);return $list;}/*** Executes the SQL and retuns all rows selected in a map that is keyed on* the property named in the keyProperty parameter. The value at each key* will be the value of the property specified in the valueProperty parameter.* If valueProperty is null, the entire result object will be entered.* @param IDbConnection database connection* @param mixed The object used to set the parameters in the SQL.* @param string The property of the result object to be used as the key.* @param string The property of the result object to be used as the value (or null).* @param callback row delegate handler* @return array An array of object containing the rows keyed by keyProperty.*/public function executeQueryForMap($connection, $parameter, $keyProperty, $valueProperty=null, $skip=-1, $max=-1, $delegate=null){$sql = $this->_command->create($this->_manager, $connection, $this->_statement, $parameter, $skip, $max);return $this->runQueryForMap($connection, $parameter, $sql, $keyProperty, $valueProperty, $delegate);}/*** Executes the SQL and retuns all rows selected in a map that is keyed on* the property named in the keyProperty parameter. The value at each key* will be the value of the property specified in the valueProperty parameter.* If valueProperty is null, the entire result object will be entered.** This method should only be called by internal developers, consider using* <tt>executeQueryForMap()</tt> first.** @param IDbConnection database connection* @param mixed The object used to set the parameters in the SQL.* @param array SQL string and subsititution parameters.* @param string The property of the result object to be used as the key.* @param string The property of the result object to be used as the value (or null).* @param callback row delegate, a callback function* @return array An array of object containing the rows keyed by keyProperty.* @see executeQueryForMap()*/public function runQueryForMap($connection, $parameter, $command, $keyProperty, $valueProperty=null, $delegate=null){$map = array();//$recordSet = $this->executeSQLQuery($connection, $sql);$connection->setActive(true);$reader = $command->query();if(!is_null($delegate)){//while($row = $recordSet->fetchRow())foreach($reader as $row){$obj = $this->applyResultMap($row);$key = TPropertyAccess::get($obj, $keyProperty);$value = is_null($valueProperty) ? $obj :TPropertyAccess::get($obj, $valueProperty);$param = new TResultSetMapItemParameter($key, $value, $parameter, $map);$this->raiseRowDelegate($delegate, $param);}}else{//while($row = $recordSet->fetchRow())foreach($reader as $row){$obj = $this->applyResultMap($row);$key = TPropertyAccess::get($obj, $keyProperty);$map[$key] = is_null($valueProperty) ? $obj :TPropertyAccess::get($obj, $valueProperty);}}$this->onExecuteQuery($command);return $map;}/*** Raises delegate handler.* This method is invoked for each new list item. It is the responsibility* of the handler to add the item to the list.* @param object event parameter*/protected function raiseRowDelegate($handler, $param){if(is_string($handler)){call_user_func($handler,$this,$param);}else if(is_callable($handler,true)){// an array: 0 - object, 1 - method name/pathlist($object,$method)=$handler;if(is_string($object)) // static method callcall_user_func($handler,$this,$param);else{if(($pos=strrpos($method,'.'))!==false){$object=$this->getSubProperty(substr($method,0,$pos));$method=substr($method,$pos+1);}$object->$method($this,$param);}}elsethrow new TInvalidDataValueException('sqlmap_invalid_delegate', $this->getID(), $handler);}/*** Executes an SQL statement that returns a single row as an object of the* type of the <tt>$result</tt> passed in as a parameter.* @param IDbConnection database connection* @param mixed The parameter data (object, arrary, primitive) used to set the parameters in the SQL* @param mixed The result object.* @return ${return}*/public function executeQueryForObject($connection, $parameter, $result=null){$sql = $this->_command->create($this->_manager, $connection, $this->_statement, $parameter);return $this->runQueryForObject($connection, $sql, $result);}/*** Executes an SQL statement that returns a single row as an object of the* type of the <tt>$result</tt> passed in as a parameter.** This method should only be called by internal developers, consider using* <tt>executeQueryForObject()</tt> first.** @param IDbConnection database connection* @param array SQL string and subsititution parameters.* @param object The result object.* @return object the object.* @see executeQueryForObject()*/public function runQueryForObject($connection, $command, &$result){$object = null;$connection->setActive(true);foreach($command->query() as $row)$object = $this->applyResultMap($row, $result);if(!$this->_groupBy->isEmpty()){$list = $this->_groupBy->collect();$this->initialGroupByResults();$object = $list[0];}$this->executePostSelect($connection);$this->onExecuteQuery($command);return $object;}/*** Execute an insert statement. Fill the parameter object with the ouput* parameters if any, also could return the insert generated key.* @param IDbConnection database connection* @param mixed The parameter object used to fill the statement.* @return string the insert generated key.*/public function executeInsert($connection, $parameter){$generatedKey = $this->getPreGeneratedSelectKey($connection, $parameter);$command = $this->_command->create($this->_manager, $connection, $this->_statement, $parameter);// var_dump($command,$parameter);$result = $command->execute();if(is_null($generatedKey))$generatedKey = $this->getPostGeneratedSelectKey($connection, $parameter);$this->executePostSelect($connection);$this->onExecuteQuery($command);return $generatedKey;}/*** Gets the insert generated ID before executing an insert statement.* @param IDbConnection database connection* @param mixed insert statement parameter.* @return string new insert ID if pre-select key statement was executed, null otherwise.*/protected function getPreGeneratedSelectKey($connection, $parameter){if($this->_statement instanceof TSqlMapInsert){$selectKey = $this->_statement->getSelectKey();if(!is_null($selectKey) && !$selectKey->getIsAfter())return $this->executeSelectKey($connection, $parameter, $selectKey);}}/*** Gets the inserted row ID after executing an insert statement.* @param IDbConnection database connection* @param mixed insert statement parameter.* @return string last insert ID, null otherwise.*/protected function getPostGeneratedSelectKey($connection, $parameter){if($this->_statement instanceof TSqlMapInsert){$selectKey = $this->_statement->getSelectKey();if(!is_null($selectKey) && $selectKey->getIsAfter())return $this->executeSelectKey($connection, $parameter, $selectKey);}}/*** Execute the select key statement, used to obtain last insert ID.* @param IDbConnection database connection* @param mixed insert statement parameter* @param TSqlMapSelectKey select key statement* @return string last insert ID.*/protected function executeSelectKey($connection, $parameter, $selectKey){$mappedStatement = $this->getManager()->getMappedStatement($selectKey->getID());$generatedKey = $mappedStatement->executeQueryForObject($connection, $parameter, null);if(strlen($prop = $selectKey->getProperty()) > 0)TPropertyAccess::set($parameter, $prop, $generatedKey);return $generatedKey;}/*** Execute an update statement. Also used for delete statement.* Return the number of rows effected.* @param IDbConnection database connection* @param mixed The object used to set the parameters in the SQL.* @return integer The number of rows effected.*/public function executeUpdate($connection, $parameter){$sql = $this->_command->create($this->getManager(),$connection, $this->_statement, $parameter);$affectedRows = $sql->execute();//$this->executeSQLQuery($connection, $sql);$this->executePostSelect($connection);$this->onExecuteQuery($sql);return $affectedRows;}/*** Process 'select' result properties* @param IDbConnection database connection*/protected function executePostSelect($connection){while(count($this->_selectQueque)){$postSelect = array_shift($this->_selectQueque);$method = $postSelect->getMethod();$statement = $postSelect->getStatement();$property = $postSelect->getResultProperty()->getProperty();$keys = $postSelect->getKeys();$resultObject = $postSelect->getResultObject();if($method == self::QUERY_FOR_LIST || $method == self::QUERY_FOR_ARRAY){$values = $statement->executeQueryForList($connection, $keys, null);if($method == self::QUERY_FOR_ARRAY)$values = $values->toArray();TPropertyAccess::set($resultObject, $property, $values);}else if($method == self::QUERY_FOR_OBJECT){$value = $statement->executeQueryForObject($connection, $keys, null);TPropertyAccess::set($resultObject, $property, $value);}}}/*** Raise the execute query event.* @param array prepared SQL statement and subsititution parameters*/public function onExecuteQuery($sql){$this->raiseEvent('OnExecuteQuery', $this, $sql);}/*** Apply result mapping.* @param array a result set row retrieved from the database* @param object the result object, will create if necessary.* @return object the result filled with data, null if not filled.*/protected function applyResultMap($row, &$resultObject=null){if($row === false) return null;$resultMapName = $this->_statement->getResultMap();$resultClass = $this->_statement->getResultClass();$obj=null;if($this->getManager()->getResultMaps()->contains($resultMapName))$obj = $this->fillResultMap($resultMapName, $row, null, $resultObject);else if(strlen($resultClass) > 0)$obj = $this->fillResultClass($resultClass, $row, $resultObject);else$obj = $this->fillDefaultResultMap(null, $row, $resultObject);if(class_exists('TActiveRecord',false) && $obj instanceof TActiveRecord)//Create a new clean active record.$obj=TActiveRecord::createRecord(get_class($obj),$obj);return $obj;}/*** Fill the result using ResultClass, will creates new result object if required.* @param string result object class name* @param array a result set row retrieved from the database* @param object the result object, will create if necessary.* @return object result object filled with data*/protected function fillResultClass($resultClass, $row, $resultObject){if(is_null($resultObject)){$registry = $this->getManager()->getTypeHandlers();$resultObject = $this->_statement->createInstanceOfResultClass($registry,$row);}if($resultObject instanceOf ArrayAccess)return $this->fillResultArrayList($row, $resultObject);else if(is_object($resultObject))return $this->fillResultObjectProperty($row, $resultObject);elsereturn $this->fillDefaultResultMap(null, $row, $resultObject);}/*** Apply the result to a TList or an array.* @param array a result set row retrieved from the database* @param object result object, array or list* @return object result filled with data.*/protected function fillResultArrayList($row, $resultObject){if($resultObject instanceof TList)foreach($row as $v)$resultObject[] = $v;elseforeach($row as $k => $v)$resultObject[$k] = $v;return $resultObject;}/*** Apply the result to an object.* @param array a result set row retrieved from the database* @param object result object, array or list* @return object result filled with data.*/protected function fillResultObjectProperty($row, $resultObject){$index = 0;$registry=$this->getManager()->getTypeHandlers();foreach($row as $k=>$v){$property = new TResultProperty;if(is_string($k) && strlen($k) > 0)$property->setColumn($k);$property->setColumnIndex(++$index);$type = gettype(TPropertyAccess::get($resultObject,$k));$property->setType($type);$value = $property->getPropertyValue($registry,$row);TPropertyAccess::set($resultObject, $k,$value);}return $resultObject;}/*** Fills the result object according to result mappings.* @param string result map name.* @param array a result set row retrieved from the database* @param object result object to fill, will create new instances if required.* @return object result object filled with data.*/protected function fillResultMap($resultMapName, $row, $parentGroup=null, &$resultObject=null){$resultMap = $this->getManager()->getResultMap($resultMapName);$registry = $this->getManager()->getTypeHandlers();$resultMap = $resultMap->resolveSubMap($registry,$row);if(is_null($resultObject))$resultObject = $resultMap->createInstanceOfResult($registry);if(is_object($resultObject)){if(strlen($resultMap->getGroupBy()) > 0)return $this->addResultMapGroupBy($resultMap, $row, $parentGroup, $resultObject);elseforeach($resultMap->getColumns() as $property)$this->setObjectProperty($resultMap, $property, $row, $resultObject);}else{$resultObject = $this->fillDefaultResultMap($resultMap, $row, $resultObject);}return $resultObject;}/*** ResultMap with GroupBy property. Save object collection graph in a tree* and collect the result later.* @param TResultMap result mapping details.* @param array a result set row retrieved from the database* @param object the result object* @return object result object.*/protected function addResultMapGroupBy($resultMap, $row, $parent, &$resultObject){$group = $this->getResultMapGroupKey($resultMap, $row);if(empty($parent)){$rootObject = array('object'=>$resultObject, 'property' => null);$this->_groupBy->add(null, $group, $rootObject);}foreach($resultMap->getColumns() as $property){//set properties.$this->setObjectProperty($resultMap, $property, $row, $resultObject);$nested = $property->getResultMapping();//nested propertyif($this->getManager()->getResultMaps()->contains($nested)){$nestedMap = $this->getManager()->getResultMap($nested);$groupKey = $this->getResultMapGroupKey($nestedMap, $row);//add the node reference firstif(empty($parent))$this->_groupBy->add($group, $groupKey, '');//get the nested result mapping value$value = $this->fillResultMap($nested, $row, $groupKey);//add it to the object tree graph$groupObject = array('object'=>$value, 'property' => $property->getProperty());if(empty($parent))$this->_groupBy->add($group, $groupKey, $groupObject);else$this->_groupBy->add($parent, $groupKey, $groupObject);}}return $resultObject;}/*** Gets the result 'group by' groupping key for each row.* @param TResultMap result mapping details.* @param array a result set row retrieved from the database* @return string groupping key.*/protected function getResultMapGroupKey($resultMap, $row){$groupBy = $resultMap->getGroupBy();if(isset($row[$groupBy]))return $resultMap->getID().$row[$groupBy];elsereturn $resultMap->getID().crc32(serialize($row));}/*** Fill the result map using default settings. If <tt>$resultMap</tt> is null* the result object returned will be guessed from <tt>$resultObject</tt>.* @param TResultMap result mapping details.* @param array a result set row retrieved from the database* @param object the result object* @return mixed the result object filled with data.*/protected function fillDefaultResultMap($resultMap, $row, $resultObject){if(is_null($resultObject))$resultObject='';if(!is_null($resultMap))$result = $this->fillArrayResultMap($resultMap, $row, $resultObject);else$result = $row;//if scalar result typesif(count($result) == 1 && ($type = gettype($resultObject))!= 'array')return $this->getScalarResult($result, $type);elsereturn $result;}/*** Retrieve the result map as an array.* @param TResultMap result mapping details.* @param array a result set row retrieved from the database* @param object the result object* @return array array list of result objects.*/protected function fillArrayResultMap($resultMap, $row, $resultObject){$result = array();$registry=$this->getManager()->getTypeHandlers();foreach($resultMap->getColumns() as $column){if(is_null($column->getType())&& !is_null($resultObject) && !is_object($resultObject))$column->setType(gettype($resultObject));$result[$column->getProperty()] = $column->getPropertyValue($registry,$row);}return $result;}/*** Converts the first array value to scalar value of given type.* @param array list of results* @param string scalar type.* @return mixed scalar value.*/protected function getScalarResult($result, $type){$scalar = array_shift($result);settype($scalar, $type);return $scalar;}/*** Set a property of the result object with appropriate value.* @param TResultMap result mapping details.* @param TResultProperty the result property to fill.* @param array a result set row retrieved from the database* @param object the result object*/protected function setObjectProperty($resultMap, $property, $row, &$resultObject){$select = $property->getSelect();$key = $property->getProperty();$nested = $property->getNestedResultMap();$registry=$this->getManager()->getTypeHandlers();if($key === ''){$resultObject = $property->getPropertyValue($registry,$row);}else if(strlen($select) == 0 && is_null($nested)){$value = $property->getPropertyValue($registry,$row);$this->_IsRowDataFound = $this->_IsRowDataFound || ($value != null);if(is_array($resultObject) || is_object($resultObject))TPropertyAccess::set($resultObject, $key, $value);else$resultObject = $value;}else if(!is_null($nested)){if($property->instanceOfListType($resultObject) || $property->instanceOfArrayType($resultObject)){if(strlen($resultMap->getGroupBy()) <= 0)throw new TSqlMapExecutionException('sqlmap_non_groupby_array_list_type', $resultMap->getID(),get_class($resultObject), $key);}else{$obj = $nested->createInstanceOfResult($this->getManager()->getTypeHandlers());if($this->fillPropertyWithResultMap($nested, $row, $obj) == false)$obj = null;TPropertyAccess::set($resultObject, $key, $obj);}}else //'select' ResultProperty{$this->enquequePostSelect($select, $resultMap, $property, $row, $resultObject);}}/*** Add nested result property to post select queue.* @param string post select statement ID* @param TResultMap current result mapping details.* @param TResultProperty current result property.* @param array a result set row retrieved from the database* @param object the result object*/protected function enquequePostSelect($select, $resultMap, $property, $row, $resultObject){$statement = $this->getManager()->getMappedStatement($select);$key = $this->getPostSelectKeys($resultMap, $property, $row);$postSelect = new TPostSelectBinding;$postSelect->setStatement($statement);$postSelect->setResultObject($resultObject);$postSelect->setResultProperty($property);$postSelect->setKeys($key);if($property->instanceOfListType($resultObject)){$values = null;if($property->getLazyLoad()){$values = TLazyLoadList::newInstance($statement, $key,$resultObject, $property->getProperty());TPropertyAccess::set($resultObject, $property->getProperty(), $values);}else$postSelect->setMethod(self::QUERY_FOR_LIST);}else if($property->instanceOfArrayType($resultObject))$postSelect->setMethod(self::QUERY_FOR_ARRAY);else$postSelect->setMethod(self::QUERY_FOR_OBJECT);if(!$property->getLazyLoad())array_push($this->_selectQueque, $postSelect);}/*** Finds in the post select property the SQL statement primary selection keys.* @param TResultMap result mapping details* @param TResultProperty result property* @param array current row data.* @return array list of primary key values.*/protected function getPostSelectKeys($resultMap, $property,$row){$value = $property->getColumn();if(is_int(strpos($value.',',0)) || is_int(strpos($value, '=',0))){$keys = array();foreach(explode(',', $value) as $entry){$pair =explode('=',$entry);$keys[trim($pair[0])] = $row[trim($pair[1])];}return $keys;}else{$registry=$this->getManager()->getTypeHandlers();return $property->getPropertyValue($registry,$row);}}/*** Fills the property with result mapping results.* @param TResultMap nested result mapping details.* @param array a result set row retrieved from the database* @param object the result object* @return boolean true if the data was found, false otherwise.*/protected function fillPropertyWithResultMap($resultMap, $row, &$resultObject){$dataFound = false;foreach($resultMap->getColumns() as $property){$this->_IsRowDataFound = false;$this->setObjectProperty($resultMap, $property, $row, $resultObject);$dataFound = $dataFound || $this->_IsRowDataFound;}$this->_IsRowDataFound = $dataFound;return $dataFound;}}/*** TPostSelectBinding class.** @author Wei Zhuo <weizho[at]gmail[dot]com>* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $* @package System.Data.SqlMap.Statements* @since 3.1*/class TPostSelectBinding{private $_statement=null;private $_property=null;private $_resultObject=null;private $_keys=null;private $_method=TMappedStatement::QUERY_FOR_LIST;public function getStatement(){ return $this->_statement; }public function setStatement($value){ $this->_statement = $value; }public function getResultProperty(){ return $this->_property; }public function setResultProperty($value){ $this->_property = $value; }public function getResultObject(){ return $this->_resultObject; }public function setResultObject($value){ $this->_resultObject = $value; }public function getKeys(){ return $this->_keys; }public function setKeys($value){ $this->_keys = $value; }public function getMethod(){ return $this->_method; }public function setMethod($value){ $this->_method = $value; }}/*** TSQLMapObjectCollectionTree class.** Maps object collection graphs as trees. Nodes in the collection can* be {@link add} using parent relationships. The object collections can be* build using the {@link collect} method.** @author Wei Zhuo <weizhuo[at]gmail[dot]com>* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $* @package System.Data.SqlMap.Statements* @since 3.1*/class TSqlMapObjectCollectionTree{/*** @var array object graph as tree*/private $_tree = array();/*** @var array tree node values*/private $_entries = array();/*** @var array resulting object collection*/private $_list = array();/*** @return boolean true if the graph is empty*/public function isEmpty(){return count($this->_entries) == 0;}/*** Add a new node to the object tree graph.* @param string parent node id* @param string new node id* @param mixed node value*/public function add($parent, $node, $object=''){if(isset($this->_entries[$parent]) && !is_null($this->_entries[$parent])&& isset($this->_entries[$node]) && !is_null($this->_entries[$node])){$this->_entries[$node] = $object;return;}$this->_entries[$node] = $object;if(empty($parent)){if(isset($this->_entries[$node]))return;$this->_tree[$node] = array();}$found = $this->addNode($this->_tree, $parent, $node);if(!$found && !empty($parent)){$this->_tree[$parent] = array();if(!isset($this->_entries[$parent]) || $object !== '')$this->_entries[$parent] = $object;$this->addNode($this->_tree, $parent, $node);}}/*** Find the parent node and add the new node as its child.* @param array list of nodes to check* @param string parent node id* @param string new node id* @return boolean true if parent node is found.*/protected function addNode(&$childs, $parent, $node){$found = false;reset($childs);for($i = 0, $k = count($childs); $i < $k; $i++){$key = key($childs);next($childs);if($key == $parent){$found = true;$childs[$key][$node] = array();}else{$found = $found || $this->addNode($childs[$key], $parent, $node);}}return $found;}/*** @return array object collection*/public function collect(){while(count($this->_tree) > 0)$this->collectChildren(null, $this->_tree);return $this->getCollection();}/*** @param array list of nodes to check* @return boolean true if all nodes are leaf nodes, false otherwise*/protected function hasChildren(&$nodes){$hasChildren = false;foreach($nodes as $node)if(count($node) != 0)return true;return $hasChildren;}/*** Visit all the child nodes and collect them by removing.* @param string parent node id* @param array list of child nodes.*/protected function collectChildren($parent, &$nodes){$noChildren = !$this->hasChildren($nodes);$childs = array();for(reset($nodes); $key = key($nodes);){next($nodes);if($noChildren){$childs[] = $key;unset($nodes[$key]);}else$this->collectChildren($key, $nodes[$key]);}if(count($childs) > 0)$this->onChildNodesVisited($parent, $childs);}/*** Set the object properties for all the child nodes visited.* @param string parent node id* @param array list of child nodes visited.*/protected function onChildNodesVisited($parent, $nodes){if(empty($parent) || empty($this->_entries[$parent]))return;$parentObject = $this->_entries[$parent]['object'];$property = $this->_entries[$nodes[0]]['property'];$list = TPropertyAccess::get($parentObject, $property);foreach($nodes as $node){if($list instanceof TList)$parentObject->{$property}[] = $this->_entries[$node]['object'];else if(is_array($list))$list[] = $this->_entries[$node]['object'];elsethrow new TSqlMapExecutionException('sqlmap_property_must_be_list');}if(is_array($list))TPropertyAccess::set($parentObject, $property, $list);if($this->_entries[$parent]['property'] === null)$this->_list[] = $parentObject;}/*** @return array object collection.*/protected function getCollection(){return $this->_list;}}/*** TResultSetListItemParameter class** @author Wei Zhuo <weizho[at]gmail[dot]com>* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $* @package System.Data.SqlMap.Statements* @since 3.1*/class TResultSetListItemParameter extends TComponent{private $_resultObject;private $_parameterObject;private $_list;public function __construct($result, $parameter, &$list){$this->_resultObject = $result;$this->_parameterObject = $parameter;$this->_list = &$list;}public function getResult(){return $this->_resultObject;}public function getParameter(){return $this->_parameterObject;}public function &getList(){return $this->_list;}}/*** TResultSetMapItemParameter class.** @author Wei Zhuo <weizho[at]gmail[dot]com>* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $* @package System.Data.SqlMap.Statements* @since 3.1*/class TResultSetMapItemParameter extends TComponent{private $_key;private $_value;private $_parameterObject;private $_map;public function __construct($key, $value, $parameter, &$map){$this->_key = $key;$this->_value = $value;$this->_parameterObject = $parameter;$this->_map = &$map;}public function getKey(){return $this->_key;}public function getValue(){return $this->_value;}public function getParameter(){return $this->_parameterObject;}public function &getMap(){return $this->_map;}}