| 1 |
lars |
1 |
<?php
|
|
|
2 |
/**
|
|
|
3 |
* TMappedStatement and related classes.
|
|
|
4 |
*
|
|
|
5 |
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
|
|
|
6 |
* @link http://www.pradosoft.com/
|
|
|
7 |
* @copyright Copyright © 2005-2008 PradoSoft
|
|
|
8 |
* @license http://www.pradosoft.com/license/
|
|
|
9 |
* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $
|
|
|
10 |
* @package System.Data.SqlMap.Statements
|
|
|
11 |
*/
|
|
|
12 |
|
|
|
13 |
/**
|
|
|
14 |
* TMappedStatement class executes SQL mapped statements. Mapped Statements can
|
|
|
15 |
* hold any SQL statement and use Parameter Maps and Result Maps for input and output.
|
|
|
16 |
*
|
|
|
17 |
* This class is usualy instantiated during SQLMap configuration by TSqlDomBuilder.
|
|
|
18 |
*
|
|
|
19 |
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
|
|
|
20 |
* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $
|
|
|
21 |
* @package System.Data.SqlMap.Statements
|
|
|
22 |
* @since 3.0
|
|
|
23 |
*/
|
|
|
24 |
class TMappedStatement extends TComponent implements IMappedStatement
|
|
|
25 |
{
|
|
|
26 |
/**
|
|
|
27 |
* @var TSqlMapStatement current SQL statement.
|
|
|
28 |
*/
|
|
|
29 |
private $_statement;
|
|
|
30 |
|
|
|
31 |
/**
|
|
|
32 |
* @var TPreparedCommand SQL command prepareer
|
|
|
33 |
*/
|
|
|
34 |
private $_command;
|
|
|
35 |
|
|
|
36 |
/**
|
|
|
37 |
* @var TSqlMapper sqlmap used by this mapper.
|
|
|
38 |
*/
|
|
|
39 |
private $_manager;
|
|
|
40 |
|
|
|
41 |
/**
|
|
|
42 |
* @var TPostSelectBinding[] post select statement queue.
|
|
|
43 |
*/
|
|
|
44 |
private $_selectQueque=array();
|
|
|
45 |
|
|
|
46 |
/**
|
|
|
47 |
* @var boolean true when data is mapped to a particular row.
|
|
|
48 |
*/
|
|
|
49 |
private $_IsRowDataFound = false;
|
|
|
50 |
|
|
|
51 |
/**
|
|
|
52 |
* @var TSQLMapObjectCollectionTree group by object collection tree
|
|
|
53 |
*/
|
|
|
54 |
private $_groupBy;
|
|
|
55 |
|
|
|
56 |
/**
|
|
|
57 |
* @var Post select is to query for list.
|
|
|
58 |
*/
|
|
|
59 |
const QUERY_FOR_LIST = 0;
|
|
|
60 |
|
|
|
61 |
/**
|
|
|
62 |
* @var Post select is to query for list.
|
|
|
63 |
*/
|
|
|
64 |
const QUERY_FOR_ARRAY = 1;
|
|
|
65 |
|
|
|
66 |
/**
|
|
|
67 |
* @var Post select is to query for object.
|
|
|
68 |
*/
|
|
|
69 |
const QUERY_FOR_OBJECT = 2;
|
|
|
70 |
|
|
|
71 |
/**
|
|
|
72 |
* @return string Name used to identify the TMappedStatement amongst the others.
|
|
|
73 |
* This the name of the SQL statement by default.
|
|
|
74 |
*/
|
|
|
75 |
public function getID()
|
|
|
76 |
{
|
|
|
77 |
return $this->_statement->ID;
|
|
|
78 |
}
|
|
|
79 |
|
|
|
80 |
/**
|
|
|
81 |
* @return TSqlMapStatement The SQL statment used by this MappedStatement
|
|
|
82 |
*/
|
|
|
83 |
public function getStatement()
|
|
|
84 |
{
|
|
|
85 |
return $this->_statement;
|
|
|
86 |
}
|
|
|
87 |
|
|
|
88 |
/**
|
|
|
89 |
* @return TSqlMapper The SqlMap used by this MappedStatement
|
|
|
90 |
*/
|
|
|
91 |
public function getManager()
|
|
|
92 |
{
|
|
|
93 |
return $this->_manager;
|
|
|
94 |
}
|
|
|
95 |
|
|
|
96 |
/**
|
|
|
97 |
* @return TPreparedCommand command to prepare SQL statements.
|
|
|
98 |
*/
|
|
|
99 |
public function getCommand()
|
|
|
100 |
{
|
|
|
101 |
return $this->_command;
|
|
|
102 |
}
|
|
|
103 |
|
|
|
104 |
/**
|
|
|
105 |
* Empty the group by results cache.
|
|
|
106 |
*/
|
|
|
107 |
protected function initialGroupByResults()
|
|
|
108 |
{
|
|
|
109 |
$this->_groupBy = new TSqlMapObjectCollectionTree();
|
|
|
110 |
}
|
|
|
111 |
|
|
|
112 |
/**
|
|
|
113 |
* Creates a new mapped statement.
|
|
|
114 |
* @param TSqlMapper an sqlmap.
|
|
|
115 |
* @param TSqlMapStatement An SQL statement.
|
|
|
116 |
*/
|
|
|
117 |
public function __construct(TSqlMapManager $sqlMap, TSqlMapStatement $statement)
|
|
|
118 |
{
|
|
|
119 |
$this->_manager = $sqlMap;
|
|
|
120 |
$this->_statement = $statement;
|
|
|
121 |
$this->_command = new TPreparedCommand();
|
|
|
122 |
$this->initialGroupByResults();
|
|
|
123 |
}
|
|
|
124 |
|
|
|
125 |
public function getSqlString()
|
|
|
126 |
{
|
|
|
127 |
return $this->getStatement()->getSqlText()->getPreparedStatement()->getPreparedSql();
|
|
|
128 |
}
|
|
|
129 |
|
|
|
130 |
/**
|
|
|
131 |
* Execute SQL Query.
|
|
|
132 |
* @param IDbConnection database connection
|
|
|
133 |
* @param array SQL statement and parameters.
|
|
|
134 |
* @return mixed record set if applicable.
|
|
|
135 |
* @throws TSqlMapExecutionException if execution error or false record set.
|
|
|
136 |
* @throws TSqlMapQueryExecutionException if any execution error
|
|
|
137 |
*/
|
|
|
138 |
/* protected function executeSQLQuery($connection, $sql)
|
|
|
139 |
{
|
|
|
140 |
try
|
|
|
141 |
{
|
|
|
142 |
if(!($recordSet = $connection->execute($sql['sql'],$sql['parameters'])))
|
|
|
143 |
{
|
|
|
144 |
throw new TSqlMapExecutionException(
|
|
|
145 |
'sqlmap_execution_error_no_record', $this->getID(),
|
|
|
146 |
$connection->ErrorMsg());
|
|
|
147 |
}
|
|
|
148 |
return $recordSet;
|
|
|
149 |
}
|
|
|
150 |
catch (Exception $e)
|
|
|
151 |
{
|
|
|
152 |
throw new TSqlMapQueryExecutionException($this->getStatement(), $e);
|
|
|
153 |
}
|
|
|
154 |
}*/
|
|
|
155 |
|
|
|
156 |
/**
|
|
|
157 |
* Execute SQL Query with limits.
|
|
|
158 |
* @param IDbConnection database connection
|
|
|
159 |
* @param array SQL statement and parameters.
|
|
|
160 |
* @return mixed record set if applicable.
|
|
|
161 |
* @throws TSqlMapExecutionException if execution error or false record set.
|
|
|
162 |
* @throws TSqlMapQueryExecutionException if any execution error
|
|
|
163 |
*/
|
|
|
164 |
protected function executeSQLQueryLimit($connection, $command, $max, $skip)
|
|
|
165 |
{
|
|
|
166 |
if($max>-1 || $skip > -1)
|
|
|
167 |
{
|
|
|
168 |
$maxStr=$max>0?' LIMIT '.$max:'';
|
|
|
169 |
$skipStr=$skip>0?' OFFSET '.$skip:'';
|
|
|
170 |
$command->setText($command->getText().$maxStr.$skipStr);
|
|
|
171 |
}
|
|
|
172 |
$connection->setActive(true);
|
|
|
173 |
return $command->query();
|
|
|
174 |
|
|
|
175 |
/*//var_dump($command);
|
|
|
176 |
try
|
|
|
177 |
{
|
|
|
178 |
$recordSet = $connection->selectLimit($sql['sql'],$max,$skip,$sql['parameters']);
|
|
|
179 |
if(!$recordSet)
|
|
|
180 |
{
|
|
|
181 |
throw new TSqlMapExecutionException(
|
|
|
182 |
'sqlmap_execution_error_query_for_list',
|
|
|
183 |
$connection->ErrorMsg());
|
|
|
184 |
}
|
|
|
185 |
return $recordSet;
|
|
|
186 |
}
|
|
|
187 |
catch (Exception $e)
|
|
|
188 |
{
|
|
|
189 |
throw new TSqlMapQueryExecutionException($this->getStatement(), $e);
|
|
|
190 |
}*/
|
|
|
191 |
}
|
|
|
192 |
|
|
|
193 |
/**
|
|
|
194 |
* Executes the SQL and retuns a List of result objects.
|
|
|
195 |
* @param IDbConnection database connection
|
|
|
196 |
* @param mixed The object used to set the parameters in the SQL.
|
|
|
197 |
* @param object result collection object.
|
|
|
198 |
* @param integer The number of rows to skip over.
|
|
|
199 |
* @param integer The maximum number of rows to return.
|
|
|
200 |
* @return array a list of result objects
|
|
|
201 |
* @param callback row delegate handler
|
|
|
202 |
* @see executeQueryForList()
|
|
|
203 |
*/
|
|
|
204 |
public function executeQueryForList($connection, $parameter, $result=null, $skip=-1, $max=-1, $delegate=null)
|
|
|
205 |
{
|
|
|
206 |
$sql = $this->_command->create($this->_manager, $connection, $this->_statement, $parameter,$skip,$max);
|
|
|
207 |
return $this->runQueryForList($connection, $parameter, $sql, $result, $delegate);
|
|
|
208 |
}
|
|
|
209 |
|
|
|
210 |
/**
|
|
|
211 |
* Executes the SQL and retuns a List of result objects.
|
|
|
212 |
*
|
|
|
213 |
* This method should only be called by internal developers, consider using
|
|
|
214 |
* <tt>executeQueryForList()</tt> first.
|
|
|
215 |
*
|
|
|
216 |
* @param IDbConnection database connection
|
|
|
217 |
* @param mixed The object used to set the parameters in the SQL.
|
|
|
218 |
* @param array SQL string and subsititution parameters.
|
|
|
219 |
* @param object result collection object.
|
|
|
220 |
* @param integer The number of rows to skip over.
|
|
|
221 |
* @param integer The maximum number of rows to return.
|
|
|
222 |
* @param callback row delegate handler
|
|
|
223 |
* @return array a list of result objects
|
|
|
224 |
* @see executeQueryForList()
|
|
|
225 |
*/
|
|
|
226 |
public function runQueryForList($connection, $parameter, $sql, $result, $delegate=null)
|
|
|
227 |
{
|
|
|
228 |
$registry=$this->getManager()->getTypeHandlers();
|
|
|
229 |
$list = $result instanceof ArrayAccess ? $result :
|
|
|
230 |
$this->_statement->createInstanceOfListClass($registry);
|
|
|
231 |
$connection->setActive(true);
|
|
|
232 |
$reader = $sql->query();
|
|
|
233 |
//$reader = $this->executeSQLQueryLimit($connection, $sql, $max, $skip);
|
|
|
234 |
if(!is_null($delegate))
|
|
|
235 |
{
|
|
|
236 |
foreach($reader as $row)
|
|
|
237 |
{
|
|
|
238 |
$obj = $this->applyResultMap($row);
|
|
|
239 |
$param = new TResultSetListItemParameter($obj, $parameter, $list);
|
|
|
240 |
$this->raiseRowDelegate($delegate, $param);
|
|
|
241 |
}
|
|
|
242 |
}
|
|
|
243 |
else
|
|
|
244 |
{
|
|
|
245 |
//var_dump($sql,$parameter);
|
|
|
246 |
foreach($reader as $row)
|
|
|
247 |
{
|
|
|
248 |
// var_dump($row);
|
|
|
249 |
$list[] = $this->applyResultMap($row);
|
|
|
250 |
}
|
|
|
251 |
}
|
|
|
252 |
|
|
|
253 |
if(!$this->_groupBy->isEmpty())
|
|
|
254 |
{
|
|
|
255 |
$list = $this->_groupBy->collect();
|
|
|
256 |
$this->initialGroupByResults();
|
|
|
257 |
}
|
|
|
258 |
|
|
|
259 |
$this->executePostSelect($connection);
|
|
|
260 |
$this->onExecuteQuery($sql);
|
|
|
261 |
|
|
|
262 |
return $list;
|
|
|
263 |
}
|
|
|
264 |
|
|
|
265 |
/**
|
|
|
266 |
* Executes the SQL and retuns all rows selected in a map that is keyed on
|
|
|
267 |
* the property named in the keyProperty parameter. The value at each key
|
|
|
268 |
* will be the value of the property specified in the valueProperty parameter.
|
|
|
269 |
* If valueProperty is null, the entire result object will be entered.
|
|
|
270 |
* @param IDbConnection database connection
|
|
|
271 |
* @param mixed The object used to set the parameters in the SQL.
|
|
|
272 |
* @param string The property of the result object to be used as the key.
|
|
|
273 |
* @param string The property of the result object to be used as the value (or null).
|
|
|
274 |
* @param callback row delegate handler
|
|
|
275 |
* @return array An array of object containing the rows keyed by keyProperty.
|
|
|
276 |
*/
|
|
|
277 |
public function executeQueryForMap($connection, $parameter, $keyProperty, $valueProperty=null, $skip=-1, $max=-1, $delegate=null)
|
|
|
278 |
{
|
|
|
279 |
$sql = $this->_command->create($this->_manager, $connection, $this->_statement, $parameter, $skip, $max);
|
|
|
280 |
return $this->runQueryForMap($connection, $parameter, $sql, $keyProperty, $valueProperty, $delegate);
|
|
|
281 |
}
|
|
|
282 |
|
|
|
283 |
/**
|
|
|
284 |
* Executes the SQL and retuns all rows selected in a map that is keyed on
|
|
|
285 |
* the property named in the keyProperty parameter. The value at each key
|
|
|
286 |
* will be the value of the property specified in the valueProperty parameter.
|
|
|
287 |
* If valueProperty is null, the entire result object will be entered.
|
|
|
288 |
*
|
|
|
289 |
* This method should only be called by internal developers, consider using
|
|
|
290 |
* <tt>executeQueryForMap()</tt> first.
|
|
|
291 |
*
|
|
|
292 |
* @param IDbConnection database connection
|
|
|
293 |
* @param mixed The object used to set the parameters in the SQL.
|
|
|
294 |
* @param array SQL string and subsititution parameters.
|
|
|
295 |
* @param string The property of the result object to be used as the key.
|
|
|
296 |
* @param string The property of the result object to be used as the value (or null).
|
|
|
297 |
* @param callback row delegate, a callback function
|
|
|
298 |
* @return array An array of object containing the rows keyed by keyProperty.
|
|
|
299 |
* @see executeQueryForMap()
|
|
|
300 |
*/
|
|
|
301 |
public function runQueryForMap($connection, $parameter, $command, $keyProperty, $valueProperty=null, $delegate=null)
|
|
|
302 |
{
|
|
|
303 |
$map = array();
|
|
|
304 |
//$recordSet = $this->executeSQLQuery($connection, $sql);
|
|
|
305 |
$connection->setActive(true);
|
|
|
306 |
$reader = $command->query();
|
|
|
307 |
if(!is_null($delegate))
|
|
|
308 |
{
|
|
|
309 |
//while($row = $recordSet->fetchRow())
|
|
|
310 |
foreach($reader as $row)
|
|
|
311 |
{
|
|
|
312 |
$obj = $this->applyResultMap($row);
|
|
|
313 |
$key = TPropertyAccess::get($obj, $keyProperty);
|
|
|
314 |
$value = is_null($valueProperty) ? $obj :
|
|
|
315 |
TPropertyAccess::get($obj, $valueProperty);
|
|
|
316 |
$param = new TResultSetMapItemParameter($key, $value, $parameter, $map);
|
|
|
317 |
$this->raiseRowDelegate($delegate, $param);
|
|
|
318 |
}
|
|
|
319 |
}
|
|
|
320 |
else
|
|
|
321 |
{
|
|
|
322 |
//while($row = $recordSet->fetchRow())
|
|
|
323 |
foreach($reader as $row)
|
|
|
324 |
{
|
|
|
325 |
$obj = $this->applyResultMap($row);
|
|
|
326 |
$key = TPropertyAccess::get($obj, $keyProperty);
|
|
|
327 |
$map[$key] = is_null($valueProperty) ? $obj :
|
|
|
328 |
TPropertyAccess::get($obj, $valueProperty);
|
|
|
329 |
}
|
|
|
330 |
}
|
|
|
331 |
$this->onExecuteQuery($command);
|
|
|
332 |
return $map;
|
|
|
333 |
}
|
|
|
334 |
|
|
|
335 |
/**
|
|
|
336 |
* Raises delegate handler.
|
|
|
337 |
* This method is invoked for each new list item. It is the responsibility
|
|
|
338 |
* of the handler to add the item to the list.
|
|
|
339 |
* @param object event parameter
|
|
|
340 |
*/
|
|
|
341 |
protected function raiseRowDelegate($handler, $param)
|
|
|
342 |
{
|
|
|
343 |
if(is_string($handler))
|
|
|
344 |
{
|
|
|
345 |
call_user_func($handler,$this,$param);
|
|
|
346 |
}
|
|
|
347 |
else if(is_callable($handler,true))
|
|
|
348 |
{
|
|
|
349 |
// an array: 0 - object, 1 - method name/path
|
|
|
350 |
list($object,$method)=$handler;
|
|
|
351 |
if(is_string($object)) // static method call
|
|
|
352 |
call_user_func($handler,$this,$param);
|
|
|
353 |
else
|
|
|
354 |
{
|
|
|
355 |
if(($pos=strrpos($method,'.'))!==false)
|
|
|
356 |
{
|
|
|
357 |
$object=$this->getSubProperty(substr($method,0,$pos));
|
|
|
358 |
$method=substr($method,$pos+1);
|
|
|
359 |
}
|
|
|
360 |
$object->$method($this,$param);
|
|
|
361 |
}
|
|
|
362 |
}
|
|
|
363 |
else
|
|
|
364 |
throw new TInvalidDataValueException('sqlmap_invalid_delegate', $this->getID(), $handler);
|
|
|
365 |
}
|
|
|
366 |
|
|
|
367 |
/**
|
|
|
368 |
* Executes an SQL statement that returns a single row as an object of the
|
|
|
369 |
* type of the <tt>$result</tt> passed in as a parameter.
|
|
|
370 |
* @param IDbConnection database connection
|
|
|
371 |
* @param mixed The parameter data (object, arrary, primitive) used to set the parameters in the SQL
|
|
|
372 |
* @param mixed The result object.
|
|
|
373 |
* @return ${return}
|
|
|
374 |
*/
|
|
|
375 |
public function executeQueryForObject($connection, $parameter, $result=null)
|
|
|
376 |
{
|
|
|
377 |
$sql = $this->_command->create($this->_manager, $connection, $this->_statement, $parameter);
|
|
|
378 |
return $this->runQueryForObject($connection, $sql, $result);
|
|
|
379 |
}
|
|
|
380 |
|
|
|
381 |
/**
|
|
|
382 |
* Executes an SQL statement that returns a single row as an object of the
|
|
|
383 |
* type of the <tt>$result</tt> passed in as a parameter.
|
|
|
384 |
*
|
|
|
385 |
* This method should only be called by internal developers, consider using
|
|
|
386 |
* <tt>executeQueryForObject()</tt> first.
|
|
|
387 |
*
|
|
|
388 |
* @param IDbConnection database connection
|
|
|
389 |
* @param array SQL string and subsititution parameters.
|
|
|
390 |
* @param object The result object.
|
|
|
391 |
* @return object the object.
|
|
|
392 |
* @see executeQueryForObject()
|
|
|
393 |
*/
|
|
|
394 |
public function runQueryForObject($connection, $command, &$result)
|
|
|
395 |
{
|
|
|
396 |
$object = null;
|
|
|
397 |
$connection->setActive(true);
|
|
|
398 |
foreach($command->query() as $row)
|
|
|
399 |
$object = $this->applyResultMap($row, $result);
|
|
|
400 |
|
|
|
401 |
if(!$this->_groupBy->isEmpty())
|
|
|
402 |
{
|
|
|
403 |
$list = $this->_groupBy->collect();
|
|
|
404 |
$this->initialGroupByResults();
|
|
|
405 |
$object = $list[0];
|
|
|
406 |
}
|
|
|
407 |
|
|
|
408 |
$this->executePostSelect($connection);
|
|
|
409 |
$this->onExecuteQuery($command);
|
|
|
410 |
|
|
|
411 |
return $object;
|
|
|
412 |
}
|
|
|
413 |
|
|
|
414 |
/**
|
|
|
415 |
* Execute an insert statement. Fill the parameter object with the ouput
|
|
|
416 |
* parameters if any, also could return the insert generated key.
|
|
|
417 |
* @param IDbConnection database connection
|
|
|
418 |
* @param mixed The parameter object used to fill the statement.
|
|
|
419 |
* @return string the insert generated key.
|
|
|
420 |
*/
|
|
|
421 |
public function executeInsert($connection, $parameter)
|
|
|
422 |
{
|
|
|
423 |
$generatedKey = $this->getPreGeneratedSelectKey($connection, $parameter);
|
|
|
424 |
|
|
|
425 |
$command = $this->_command->create($this->_manager, $connection, $this->_statement, $parameter);
|
|
|
426 |
// var_dump($command,$parameter);
|
|
|
427 |
$result = $command->execute();
|
|
|
428 |
|
|
|
429 |
if(is_null($generatedKey))
|
|
|
430 |
$generatedKey = $this->getPostGeneratedSelectKey($connection, $parameter);
|
|
|
431 |
|
|
|
432 |
$this->executePostSelect($connection);
|
|
|
433 |
$this->onExecuteQuery($command);
|
|
|
434 |
return $generatedKey;
|
|
|
435 |
}
|
|
|
436 |
|
|
|
437 |
/**
|
|
|
438 |
* Gets the insert generated ID before executing an insert statement.
|
|
|
439 |
* @param IDbConnection database connection
|
|
|
440 |
* @param mixed insert statement parameter.
|
|
|
441 |
* @return string new insert ID if pre-select key statement was executed, null otherwise.
|
|
|
442 |
*/
|
|
|
443 |
protected function getPreGeneratedSelectKey($connection, $parameter)
|
|
|
444 |
{
|
|
|
445 |
if($this->_statement instanceof TSqlMapInsert)
|
|
|
446 |
{
|
|
|
447 |
$selectKey = $this->_statement->getSelectKey();
|
|
|
448 |
if(!is_null($selectKey) && !$selectKey->getIsAfter())
|
|
|
449 |
return $this->executeSelectKey($connection, $parameter, $selectKey);
|
|
|
450 |
}
|
|
|
451 |
}
|
|
|
452 |
|
|
|
453 |
/**
|
|
|
454 |
* Gets the inserted row ID after executing an insert statement.
|
|
|
455 |
* @param IDbConnection database connection
|
|
|
456 |
* @param mixed insert statement parameter.
|
|
|
457 |
* @return string last insert ID, null otherwise.
|
|
|
458 |
*/
|
|
|
459 |
protected function getPostGeneratedSelectKey($connection, $parameter)
|
|
|
460 |
{
|
|
|
461 |
if($this->_statement instanceof TSqlMapInsert)
|
|
|
462 |
{
|
|
|
463 |
$selectKey = $this->_statement->getSelectKey();
|
|
|
464 |
if(!is_null($selectKey) && $selectKey->getIsAfter())
|
|
|
465 |
return $this->executeSelectKey($connection, $parameter, $selectKey);
|
|
|
466 |
}
|
|
|
467 |
}
|
|
|
468 |
|
|
|
469 |
/**
|
|
|
470 |
* Execute the select key statement, used to obtain last insert ID.
|
|
|
471 |
* @param IDbConnection database connection
|
|
|
472 |
* @param mixed insert statement parameter
|
|
|
473 |
* @param TSqlMapSelectKey select key statement
|
|
|
474 |
* @return string last insert ID.
|
|
|
475 |
*/
|
|
|
476 |
protected function executeSelectKey($connection, $parameter, $selectKey)
|
|
|
477 |
{
|
|
|
478 |
$mappedStatement = $this->getManager()->getMappedStatement($selectKey->getID());
|
|
|
479 |
$generatedKey = $mappedStatement->executeQueryForObject(
|
|
|
480 |
$connection, $parameter, null);
|
|
|
481 |
if(strlen($prop = $selectKey->getProperty()) > 0)
|
|
|
482 |
TPropertyAccess::set($parameter, $prop, $generatedKey);
|
|
|
483 |
return $generatedKey;
|
|
|
484 |
}
|
|
|
485 |
|
|
|
486 |
/**
|
|
|
487 |
* Execute an update statement. Also used for delete statement.
|
|
|
488 |
* Return the number of rows effected.
|
|
|
489 |
* @param IDbConnection database connection
|
|
|
490 |
* @param mixed The object used to set the parameters in the SQL.
|
|
|
491 |
* @return integer The number of rows effected.
|
|
|
492 |
*/
|
|
|
493 |
public function executeUpdate($connection, $parameter)
|
|
|
494 |
{
|
|
|
495 |
$sql = $this->_command->create($this->getManager(),$connection, $this->_statement, $parameter);
|
|
|
496 |
$affectedRows = $sql->execute();
|
|
|
497 |
//$this->executeSQLQuery($connection, $sql);
|
|
|
498 |
$this->executePostSelect($connection);
|
|
|
499 |
$this->onExecuteQuery($sql);
|
|
|
500 |
return $affectedRows;
|
|
|
501 |
}
|
|
|
502 |
|
|
|
503 |
/**
|
|
|
504 |
* Process 'select' result properties
|
|
|
505 |
* @param IDbConnection database connection
|
|
|
506 |
*/
|
|
|
507 |
protected function executePostSelect($connection)
|
|
|
508 |
{
|
|
|
509 |
while(count($this->_selectQueque))
|
|
|
510 |
{
|
|
|
511 |
$postSelect = array_shift($this->_selectQueque);
|
|
|
512 |
$method = $postSelect->getMethod();
|
|
|
513 |
$statement = $postSelect->getStatement();
|
|
|
514 |
$property = $postSelect->getResultProperty()->getProperty();
|
|
|
515 |
$keys = $postSelect->getKeys();
|
|
|
516 |
$resultObject = $postSelect->getResultObject();
|
|
|
517 |
|
|
|
518 |
if($method == self::QUERY_FOR_LIST || $method == self::QUERY_FOR_ARRAY)
|
|
|
519 |
{
|
|
|
520 |
$values = $statement->executeQueryForList($connection, $keys, null);
|
|
|
521 |
|
|
|
522 |
if($method == self::QUERY_FOR_ARRAY)
|
|
|
523 |
$values = $values->toArray();
|
|
|
524 |
TPropertyAccess::set($resultObject, $property, $values);
|
|
|
525 |
}
|
|
|
526 |
else if($method == self::QUERY_FOR_OBJECT)
|
|
|
527 |
{
|
|
|
528 |
$value = $statement->executeQueryForObject($connection, $keys, null);
|
|
|
529 |
TPropertyAccess::set($resultObject, $property, $value);
|
|
|
530 |
}
|
|
|
531 |
}
|
|
|
532 |
}
|
|
|
533 |
|
|
|
534 |
/**
|
|
|
535 |
* Raise the execute query event.
|
|
|
536 |
* @param array prepared SQL statement and subsititution parameters
|
|
|
537 |
*/
|
|
|
538 |
public function onExecuteQuery($sql)
|
|
|
539 |
{
|
|
|
540 |
$this->raiseEvent('OnExecuteQuery', $this, $sql);
|
|
|
541 |
}
|
|
|
542 |
|
|
|
543 |
/**
|
|
|
544 |
* Apply result mapping.
|
|
|
545 |
* @param array a result set row retrieved from the database
|
|
|
546 |
* @param object the result object, will create if necessary.
|
|
|
547 |
* @return object the result filled with data, null if not filled.
|
|
|
548 |
*/
|
|
|
549 |
protected function applyResultMap($row, &$resultObject=null)
|
|
|
550 |
{
|
|
|
551 |
if($row === false) return null;
|
|
|
552 |
|
|
|
553 |
$resultMapName = $this->_statement->getResultMap();
|
|
|
554 |
$resultClass = $this->_statement->getResultClass();
|
|
|
555 |
|
|
|
556 |
$obj=null;
|
|
|
557 |
if($this->getManager()->getResultMaps()->contains($resultMapName))
|
|
|
558 |
$obj = $this->fillResultMap($resultMapName, $row, null, $resultObject);
|
|
|
559 |
else if(strlen($resultClass) > 0)
|
|
|
560 |
$obj = $this->fillResultClass($resultClass, $row, $resultObject);
|
|
|
561 |
else
|
|
|
562 |
$obj = $this->fillDefaultResultMap(null, $row, $resultObject);
|
|
|
563 |
if(class_exists('TActiveRecord',false) && $obj instanceof TActiveRecord)
|
|
|
564 |
//Create a new clean active record.
|
|
|
565 |
$obj=TActiveRecord::createRecord(get_class($obj),$obj);
|
|
|
566 |
return $obj;
|
|
|
567 |
}
|
|
|
568 |
|
|
|
569 |
/**
|
|
|
570 |
* Fill the result using ResultClass, will creates new result object if required.
|
|
|
571 |
* @param string result object class name
|
|
|
572 |
* @param array a result set row retrieved from the database
|
|
|
573 |
* @param object the result object, will create if necessary.
|
|
|
574 |
* @return object result object filled with data
|
|
|
575 |
*/
|
|
|
576 |
protected function fillResultClass($resultClass, $row, $resultObject)
|
|
|
577 |
{
|
|
|
578 |
if(is_null($resultObject))
|
|
|
579 |
{
|
|
|
580 |
$registry = $this->getManager()->getTypeHandlers();
|
|
|
581 |
$resultObject = $this->_statement->createInstanceOfResultClass($registry,$row);
|
|
|
582 |
}
|
|
|
583 |
|
|
|
584 |
if($resultObject instanceOf ArrayAccess)
|
|
|
585 |
return $this->fillResultArrayList($row, $resultObject);
|
|
|
586 |
else if(is_object($resultObject))
|
|
|
587 |
return $this->fillResultObjectProperty($row, $resultObject);
|
|
|
588 |
else
|
|
|
589 |
return $this->fillDefaultResultMap(null, $row, $resultObject);
|
|
|
590 |
}
|
|
|
591 |
|
|
|
592 |
/**
|
|
|
593 |
* Apply the result to a TList or an array.
|
|
|
594 |
* @param array a result set row retrieved from the database
|
|
|
595 |
* @param object result object, array or list
|
|
|
596 |
* @return object result filled with data.
|
|
|
597 |
*/
|
|
|
598 |
protected function fillResultArrayList($row, $resultObject)
|
|
|
599 |
{
|
|
|
600 |
if($resultObject instanceof TList)
|
|
|
601 |
foreach($row as $v)
|
|
|
602 |
$resultObject[] = $v;
|
|
|
603 |
else
|
|
|
604 |
foreach($row as $k => $v)
|
|
|
605 |
$resultObject[$k] = $v;
|
|
|
606 |
return $resultObject;
|
|
|
607 |
}
|
|
|
608 |
|
|
|
609 |
/**
|
|
|
610 |
* Apply the result to an object.
|
|
|
611 |
* @param array a result set row retrieved from the database
|
|
|
612 |
* @param object result object, array or list
|
|
|
613 |
* @return object result filled with data.
|
|
|
614 |
*/
|
|
|
615 |
protected function fillResultObjectProperty($row, $resultObject)
|
|
|
616 |
{
|
|
|
617 |
$index = 0;
|
|
|
618 |
$registry=$this->getManager()->getTypeHandlers();
|
|
|
619 |
foreach($row as $k=>$v)
|
|
|
620 |
{
|
|
|
621 |
$property = new TResultProperty;
|
|
|
622 |
if(is_string($k) && strlen($k) > 0)
|
|
|
623 |
$property->setColumn($k);
|
|
|
624 |
$property->setColumnIndex(++$index);
|
|
|
625 |
$type = gettype(TPropertyAccess::get($resultObject,$k));
|
|
|
626 |
$property->setType($type);
|
|
|
627 |
$value = $property->getPropertyValue($registry,$row);
|
|
|
628 |
TPropertyAccess::set($resultObject, $k,$value);
|
|
|
629 |
}
|
|
|
630 |
return $resultObject;
|
|
|
631 |
}
|
|
|
632 |
|
|
|
633 |
/**
|
|
|
634 |
* Fills the result object according to result mappings.
|
|
|
635 |
* @param string result map name.
|
|
|
636 |
* @param array a result set row retrieved from the database
|
|
|
637 |
* @param object result object to fill, will create new instances if required.
|
|
|
638 |
* @return object result object filled with data.
|
|
|
639 |
*/
|
|
|
640 |
protected function fillResultMap($resultMapName, $row, $parentGroup=null, &$resultObject=null)
|
|
|
641 |
{
|
|
|
642 |
$resultMap = $this->getManager()->getResultMap($resultMapName);
|
|
|
643 |
$registry = $this->getManager()->getTypeHandlers();
|
|
|
644 |
$resultMap = $resultMap->resolveSubMap($registry,$row);
|
|
|
645 |
|
|
|
646 |
if(is_null($resultObject))
|
|
|
647 |
$resultObject = $resultMap->createInstanceOfResult($registry);
|
|
|
648 |
|
|
|
649 |
if(is_object($resultObject))
|
|
|
650 |
{
|
|
|
651 |
if(strlen($resultMap->getGroupBy()) > 0)
|
|
|
652 |
return $this->addResultMapGroupBy($resultMap, $row, $parentGroup, $resultObject);
|
|
|
653 |
else
|
|
|
654 |
foreach($resultMap->getColumns() as $property)
|
|
|
655 |
$this->setObjectProperty($resultMap, $property, $row, $resultObject);
|
|
|
656 |
}
|
|
|
657 |
else
|
|
|
658 |
{
|
|
|
659 |
$resultObject = $this->fillDefaultResultMap($resultMap, $row, $resultObject);
|
|
|
660 |
}
|
|
|
661 |
return $resultObject;
|
|
|
662 |
}
|
|
|
663 |
|
|
|
664 |
/**
|
|
|
665 |
* ResultMap with GroupBy property. Save object collection graph in a tree
|
|
|
666 |
* and collect the result later.
|
|
|
667 |
* @param TResultMap result mapping details.
|
|
|
668 |
* @param array a result set row retrieved from the database
|
|
|
669 |
* @param object the result object
|
|
|
670 |
* @return object result object.
|
|
|
671 |
*/
|
|
|
672 |
protected function addResultMapGroupBy($resultMap, $row, $parent, &$resultObject)
|
|
|
673 |
{
|
|
|
674 |
$group = $this->getResultMapGroupKey($resultMap, $row);
|
|
|
675 |
|
|
|
676 |
if(empty($parent))
|
|
|
677 |
{
|
|
|
678 |
$rootObject = array('object'=>$resultObject, 'property' => null);
|
|
|
679 |
$this->_groupBy->add(null, $group, $rootObject);
|
|
|
680 |
}
|
|
|
681 |
|
|
|
682 |
foreach($resultMap->getColumns() as $property)
|
|
|
683 |
{
|
|
|
684 |
//set properties.
|
|
|
685 |
$this->setObjectProperty($resultMap, $property, $row, $resultObject);
|
|
|
686 |
$nested = $property->getResultMapping();
|
|
|
687 |
|
|
|
688 |
//nested property
|
|
|
689 |
if($this->getManager()->getResultMaps()->contains($nested))
|
|
|
690 |
{
|
|
|
691 |
$nestedMap = $this->getManager()->getResultMap($nested);
|
|
|
692 |
$groupKey = $this->getResultMapGroupKey($nestedMap, $row);
|
|
|
693 |
|
|
|
694 |
//add the node reference first
|
|
|
695 |
if(empty($parent))
|
|
|
696 |
$this->_groupBy->add($group, $groupKey, '');
|
|
|
697 |
|
|
|
698 |
//get the nested result mapping value
|
|
|
699 |
$value = $this->fillResultMap($nested, $row, $groupKey);
|
|
|
700 |
|
|
|
701 |
//add it to the object tree graph
|
|
|
702 |
$groupObject = array('object'=>$value, 'property' => $property->getProperty());
|
|
|
703 |
if(empty($parent))
|
|
|
704 |
$this->_groupBy->add($group, $groupKey, $groupObject);
|
|
|
705 |
else
|
|
|
706 |
$this->_groupBy->add($parent, $groupKey, $groupObject);
|
|
|
707 |
}
|
|
|
708 |
}
|
|
|
709 |
return $resultObject;
|
|
|
710 |
}
|
|
|
711 |
|
|
|
712 |
/**
|
|
|
713 |
* Gets the result 'group by' groupping key for each row.
|
|
|
714 |
* @param TResultMap result mapping details.
|
|
|
715 |
* @param array a result set row retrieved from the database
|
|
|
716 |
* @return string groupping key.
|
|
|
717 |
*/
|
|
|
718 |
protected function getResultMapGroupKey($resultMap, $row)
|
|
|
719 |
{
|
|
|
720 |
$groupBy = $resultMap->getGroupBy();
|
|
|
721 |
if(isset($row[$groupBy]))
|
|
|
722 |
return $resultMap->getID().$row[$groupBy];
|
|
|
723 |
else
|
|
|
724 |
return $resultMap->getID().crc32(serialize($row));
|
|
|
725 |
}
|
|
|
726 |
|
|
|
727 |
/**
|
|
|
728 |
* Fill the result map using default settings. If <tt>$resultMap</tt> is null
|
|
|
729 |
* the result object returned will be guessed from <tt>$resultObject</tt>.
|
|
|
730 |
* @param TResultMap result mapping details.
|
|
|
731 |
* @param array a result set row retrieved from the database
|
|
|
732 |
* @param object the result object
|
|
|
733 |
* @return mixed the result object filled with data.
|
|
|
734 |
*/
|
|
|
735 |
protected function fillDefaultResultMap($resultMap, $row, $resultObject)
|
|
|
736 |
{
|
|
|
737 |
if(is_null($resultObject))
|
|
|
738 |
$resultObject='';
|
|
|
739 |
|
|
|
740 |
if(!is_null($resultMap))
|
|
|
741 |
$result = $this->fillArrayResultMap($resultMap, $row, $resultObject);
|
|
|
742 |
else
|
|
|
743 |
$result = $row;
|
|
|
744 |
|
|
|
745 |
//if scalar result types
|
|
|
746 |
if(count($result) == 1 && ($type = gettype($resultObject))!= 'array')
|
|
|
747 |
return $this->getScalarResult($result, $type);
|
|
|
748 |
else
|
|
|
749 |
return $result;
|
|
|
750 |
}
|
|
|
751 |
|
|
|
752 |
/**
|
|
|
753 |
* Retrieve the result map as an array.
|
|
|
754 |
* @param TResultMap result mapping details.
|
|
|
755 |
* @param array a result set row retrieved from the database
|
|
|
756 |
* @param object the result object
|
|
|
757 |
* @return array array list of result objects.
|
|
|
758 |
*/
|
|
|
759 |
protected function fillArrayResultMap($resultMap, $row, $resultObject)
|
|
|
760 |
{
|
|
|
761 |
$result = array();
|
|
|
762 |
$registry=$this->getManager()->getTypeHandlers();
|
|
|
763 |
foreach($resultMap->getColumns() as $column)
|
|
|
764 |
{
|
|
|
765 |
if(is_null($column->getType())
|
|
|
766 |
&& !is_null($resultObject) && !is_object($resultObject))
|
|
|
767 |
$column->setType(gettype($resultObject));
|
|
|
768 |
$result[$column->getProperty()] = $column->getPropertyValue($registry,$row);
|
|
|
769 |
}
|
|
|
770 |
return $result;
|
|
|
771 |
}
|
|
|
772 |
|
|
|
773 |
/**
|
|
|
774 |
* Converts the first array value to scalar value of given type.
|
|
|
775 |
* @param array list of results
|
|
|
776 |
* @param string scalar type.
|
|
|
777 |
* @return mixed scalar value.
|
|
|
778 |
*/
|
|
|
779 |
protected function getScalarResult($result, $type)
|
|
|
780 |
{
|
|
|
781 |
$scalar = array_shift($result);
|
|
|
782 |
settype($scalar, $type);
|
|
|
783 |
return $scalar;
|
|
|
784 |
}
|
|
|
785 |
|
|
|
786 |
/**
|
|
|
787 |
* Set a property of the result object with appropriate value.
|
|
|
788 |
* @param TResultMap result mapping details.
|
|
|
789 |
* @param TResultProperty the result property to fill.
|
|
|
790 |
* @param array a result set row retrieved from the database
|
|
|
791 |
* @param object the result object
|
|
|
792 |
*/
|
|
|
793 |
protected function setObjectProperty($resultMap, $property, $row, &$resultObject)
|
|
|
794 |
{
|
|
|
795 |
$select = $property->getSelect();
|
|
|
796 |
$key = $property->getProperty();
|
|
|
797 |
$nested = $property->getNestedResultMap();
|
|
|
798 |
$registry=$this->getManager()->getTypeHandlers();
|
|
|
799 |
if($key === '')
|
|
|
800 |
{
|
|
|
801 |
$resultObject = $property->getPropertyValue($registry,$row);
|
|
|
802 |
}
|
|
|
803 |
else if(strlen($select) == 0 && is_null($nested))
|
|
|
804 |
{
|
|
|
805 |
$value = $property->getPropertyValue($registry,$row);
|
|
|
806 |
|
|
|
807 |
$this->_IsRowDataFound = $this->_IsRowDataFound || ($value != null);
|
|
|
808 |
if(is_array($resultObject) || is_object($resultObject))
|
|
|
809 |
TPropertyAccess::set($resultObject, $key, $value);
|
|
|
810 |
else
|
|
|
811 |
$resultObject = $value;
|
|
|
812 |
}
|
|
|
813 |
else if(!is_null($nested))
|
|
|
814 |
{
|
|
|
815 |
if($property->instanceOfListType($resultObject) || $property->instanceOfArrayType($resultObject))
|
|
|
816 |
{
|
|
|
817 |
if(strlen($resultMap->getGroupBy()) <= 0)
|
|
|
818 |
throw new TSqlMapExecutionException(
|
|
|
819 |
'sqlmap_non_groupby_array_list_type', $resultMap->getID(),
|
|
|
820 |
get_class($resultObject), $key);
|
|
|
821 |
}
|
|
|
822 |
else
|
|
|
823 |
{
|
|
|
824 |
$obj = $nested->createInstanceOfResult($this->getManager()->getTypeHandlers());
|
|
|
825 |
if($this->fillPropertyWithResultMap($nested, $row, $obj) == false)
|
|
|
826 |
$obj = null;
|
|
|
827 |
TPropertyAccess::set($resultObject, $key, $obj);
|
|
|
828 |
}
|
|
|
829 |
}
|
|
|
830 |
else //'select' ResultProperty
|
|
|
831 |
{
|
|
|
832 |
$this->enquequePostSelect($select, $resultMap, $property, $row, $resultObject);
|
|
|
833 |
}
|
|
|
834 |
}
|
|
|
835 |
|
|
|
836 |
/**
|
|
|
837 |
* Add nested result property to post select queue.
|
|
|
838 |
* @param string post select statement ID
|
|
|
839 |
* @param TResultMap current result mapping details.
|
|
|
840 |
* @param TResultProperty current result property.
|
|
|
841 |
* @param array a result set row retrieved from the database
|
|
|
842 |
* @param object the result object
|
|
|
843 |
*/
|
|
|
844 |
protected function enquequePostSelect($select, $resultMap, $property, $row, $resultObject)
|
|
|
845 |
{
|
|
|
846 |
$statement = $this->getManager()->getMappedStatement($select);
|
|
|
847 |
$key = $this->getPostSelectKeys($resultMap, $property, $row);
|
|
|
848 |
$postSelect = new TPostSelectBinding;
|
|
|
849 |
$postSelect->setStatement($statement);
|
|
|
850 |
$postSelect->setResultObject($resultObject);
|
|
|
851 |
$postSelect->setResultProperty($property);
|
|
|
852 |
$postSelect->setKeys($key);
|
|
|
853 |
|
|
|
854 |
if($property->instanceOfListType($resultObject))
|
|
|
855 |
{
|
|
|
856 |
$values = null;
|
|
|
857 |
if($property->getLazyLoad())
|
|
|
858 |
{
|
|
|
859 |
$values = TLazyLoadList::newInstance($statement, $key,
|
|
|
860 |
$resultObject, $property->getProperty());
|
|
|
861 |
TPropertyAccess::set($resultObject, $property->getProperty(), $values);
|
|
|
862 |
}
|
|
|
863 |
else
|
|
|
864 |
$postSelect->setMethod(self::QUERY_FOR_LIST);
|
|
|
865 |
}
|
|
|
866 |
else if($property->instanceOfArrayType($resultObject))
|
|
|
867 |
$postSelect->setMethod(self::QUERY_FOR_ARRAY);
|
|
|
868 |
else
|
|
|
869 |
$postSelect->setMethod(self::QUERY_FOR_OBJECT);
|
|
|
870 |
|
|
|
871 |
if(!$property->getLazyLoad())
|
|
|
872 |
array_push($this->_selectQueque, $postSelect);
|
|
|
873 |
}
|
|
|
874 |
|
|
|
875 |
/**
|
|
|
876 |
* Finds in the post select property the SQL statement primary selection keys.
|
|
|
877 |
* @param TResultMap result mapping details
|
|
|
878 |
* @param TResultProperty result property
|
|
|
879 |
* @param array current row data.
|
|
|
880 |
* @return array list of primary key values.
|
|
|
881 |
*/
|
|
|
882 |
protected function getPostSelectKeys($resultMap, $property,$row)
|
|
|
883 |
{
|
|
|
884 |
$value = $property->getColumn();
|
|
|
885 |
if(is_int(strpos($value.',',0)) || is_int(strpos($value, '=',0)))
|
|
|
886 |
{
|
|
|
887 |
$keys = array();
|
|
|
888 |
foreach(explode(',', $value) as $entry)
|
|
|
889 |
{
|
|
|
890 |
$pair =explode('=',$entry);
|
|
|
891 |
$keys[trim($pair[0])] = $row[trim($pair[1])];
|
|
|
892 |
}
|
|
|
893 |
return $keys;
|
|
|
894 |
}
|
|
|
895 |
else
|
|
|
896 |
{
|
|
|
897 |
$registry=$this->getManager()->getTypeHandlers();
|
|
|
898 |
return $property->getPropertyValue($registry,$row);
|
|
|
899 |
}
|
|
|
900 |
}
|
|
|
901 |
|
|
|
902 |
/**
|
|
|
903 |
* Fills the property with result mapping results.
|
|
|
904 |
* @param TResultMap nested result mapping details.
|
|
|
905 |
* @param array a result set row retrieved from the database
|
|
|
906 |
* @param object the result object
|
|
|
907 |
* @return boolean true if the data was found, false otherwise.
|
|
|
908 |
*/
|
|
|
909 |
protected function fillPropertyWithResultMap($resultMap, $row, &$resultObject)
|
|
|
910 |
{
|
|
|
911 |
$dataFound = false;
|
|
|
912 |
foreach($resultMap->getColumns() as $property)
|
|
|
913 |
{
|
|
|
914 |
$this->_IsRowDataFound = false;
|
|
|
915 |
$this->setObjectProperty($resultMap, $property, $row, $resultObject);
|
|
|
916 |
$dataFound = $dataFound || $this->_IsRowDataFound;
|
|
|
917 |
}
|
|
|
918 |
$this->_IsRowDataFound = $dataFound;
|
|
|
919 |
return $dataFound;
|
|
|
920 |
}
|
|
|
921 |
}
|
|
|
922 |
|
|
|
923 |
/**
|
|
|
924 |
* TPostSelectBinding class.
|
|
|
925 |
*
|
|
|
926 |
* @author Wei Zhuo <weizho[at]gmail[dot]com>
|
|
|
927 |
* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $
|
|
|
928 |
* @package System.Data.SqlMap.Statements
|
|
|
929 |
* @since 3.1
|
|
|
930 |
*/
|
|
|
931 |
class TPostSelectBinding
|
|
|
932 |
{
|
|
|
933 |
private $_statement=null;
|
|
|
934 |
private $_property=null;
|
|
|
935 |
private $_resultObject=null;
|
|
|
936 |
private $_keys=null;
|
|
|
937 |
private $_method=TMappedStatement::QUERY_FOR_LIST;
|
|
|
938 |
|
|
|
939 |
public function getStatement(){ return $this->_statement; }
|
|
|
940 |
public function setStatement($value){ $this->_statement = $value; }
|
|
|
941 |
|
|
|
942 |
public function getResultProperty(){ return $this->_property; }
|
|
|
943 |
public function setResultProperty($value){ $this->_property = $value; }
|
|
|
944 |
|
|
|
945 |
public function getResultObject(){ return $this->_resultObject; }
|
|
|
946 |
public function setResultObject($value){ $this->_resultObject = $value; }
|
|
|
947 |
|
|
|
948 |
public function getKeys(){ return $this->_keys; }
|
|
|
949 |
public function setKeys($value){ $this->_keys = $value; }
|
|
|
950 |
|
|
|
951 |
public function getMethod(){ return $this->_method; }
|
|
|
952 |
public function setMethod($value){ $this->_method = $value; }
|
|
|
953 |
}
|
|
|
954 |
|
|
|
955 |
/**
|
|
|
956 |
* TSQLMapObjectCollectionTree class.
|
|
|
957 |
*
|
|
|
958 |
* Maps object collection graphs as trees. Nodes in the collection can
|
|
|
959 |
* be {@link add} using parent relationships. The object collections can be
|
|
|
960 |
* build using the {@link collect} method.
|
|
|
961 |
*
|
|
|
962 |
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
|
|
|
963 |
* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $
|
|
|
964 |
* @package System.Data.SqlMap.Statements
|
|
|
965 |
* @since 3.1
|
|
|
966 |
*/
|
|
|
967 |
class TSqlMapObjectCollectionTree
|
|
|
968 |
{
|
|
|
969 |
/**
|
|
|
970 |
* @var array object graph as tree
|
|
|
971 |
*/
|
|
|
972 |
private $_tree = array();
|
|
|
973 |
/**
|
|
|
974 |
* @var array tree node values
|
|
|
975 |
*/
|
|
|
976 |
private $_entries = array();
|
|
|
977 |
/**
|
|
|
978 |
* @var array resulting object collection
|
|
|
979 |
*/
|
|
|
980 |
private $_list = array();
|
|
|
981 |
|
|
|
982 |
/**
|
|
|
983 |
* @return boolean true if the graph is empty
|
|
|
984 |
*/
|
|
|
985 |
public function isEmpty()
|
|
|
986 |
{
|
|
|
987 |
return count($this->_entries) == 0;
|
|
|
988 |
}
|
|
|
989 |
|
|
|
990 |
/**
|
|
|
991 |
* Add a new node to the object tree graph.
|
|
|
992 |
* @param string parent node id
|
|
|
993 |
* @param string new node id
|
|
|
994 |
* @param mixed node value
|
|
|
995 |
*/
|
|
|
996 |
public function add($parent, $node, $object='')
|
|
|
997 |
{
|
|
|
998 |
if(isset($this->_entries[$parent]) && !is_null($this->_entries[$parent])
|
|
|
999 |
&& isset($this->_entries[$node]) && !is_null($this->_entries[$node]))
|
|
|
1000 |
{
|
|
|
1001 |
$this->_entries[$node] = $object;
|
|
|
1002 |
return;
|
|
|
1003 |
}
|
|
|
1004 |
$this->_entries[$node] = $object;
|
|
|
1005 |
if(empty($parent))
|
|
|
1006 |
{
|
|
|
1007 |
if(isset($this->_entries[$node]))
|
|
|
1008 |
return;
|
|
|
1009 |
$this->_tree[$node] = array();
|
|
|
1010 |
}
|
|
|
1011 |
$found = $this->addNode($this->_tree, $parent, $node);
|
|
|
1012 |
if(!$found && !empty($parent))
|
|
|
1013 |
{
|
|
|
1014 |
$this->_tree[$parent] = array();
|
|
|
1015 |
if(!isset($this->_entries[$parent]) || $object !== '')
|
|
|
1016 |
$this->_entries[$parent] = $object;
|
|
|
1017 |
$this->addNode($this->_tree, $parent, $node);
|
|
|
1018 |
}
|
|
|
1019 |
}
|
|
|
1020 |
|
|
|
1021 |
/**
|
|
|
1022 |
* Find the parent node and add the new node as its child.
|
|
|
1023 |
* @param array list of nodes to check
|
|
|
1024 |
* @param string parent node id
|
|
|
1025 |
* @param string new node id
|
|
|
1026 |
* @return boolean true if parent node is found.
|
|
|
1027 |
*/
|
|
|
1028 |
protected function addNode(&$childs, $parent, $node)
|
|
|
1029 |
{
|
|
|
1030 |
$found = false;
|
|
|
1031 |
reset($childs);
|
|
|
1032 |
for($i = 0, $k = count($childs); $i < $k; $i++)
|
|
|
1033 |
{
|
|
|
1034 |
$key = key($childs);
|
|
|
1035 |
next($childs);
|
|
|
1036 |
if($key == $parent)
|
|
|
1037 |
{
|
|
|
1038 |
$found = true;
|
|
|
1039 |
$childs[$key][$node] = array();
|
|
|
1040 |
}
|
|
|
1041 |
else
|
|
|
1042 |
{
|
|
|
1043 |
$found = $found || $this->addNode($childs[$key], $parent, $node);
|
|
|
1044 |
}
|
|
|
1045 |
}
|
|
|
1046 |
return $found;
|
|
|
1047 |
}
|
|
|
1048 |
|
|
|
1049 |
/**
|
|
|
1050 |
* @return array object collection
|
|
|
1051 |
*/
|
|
|
1052 |
public function collect()
|
|
|
1053 |
{
|
|
|
1054 |
while(count($this->_tree) > 0)
|
|
|
1055 |
$this->collectChildren(null, $this->_tree);
|
|
|
1056 |
return $this->getCollection();
|
|
|
1057 |
}
|
|
|
1058 |
|
|
|
1059 |
/**
|
|
|
1060 |
* @param array list of nodes to check
|
|
|
1061 |
* @return boolean true if all nodes are leaf nodes, false otherwise
|
|
|
1062 |
*/
|
|
|
1063 |
protected function hasChildren(&$nodes)
|
|
|
1064 |
{
|
|
|
1065 |
$hasChildren = false;
|
|
|
1066 |
foreach($nodes as $node)
|
|
|
1067 |
if(count($node) != 0)
|
|
|
1068 |
return true;
|
|
|
1069 |
return $hasChildren;
|
|
|
1070 |
}
|
|
|
1071 |
|
|
|
1072 |
/**
|
|
|
1073 |
* Visit all the child nodes and collect them by removing.
|
|
|
1074 |
* @param string parent node id
|
|
|
1075 |
* @param array list of child nodes.
|
|
|
1076 |
*/
|
|
|
1077 |
protected function collectChildren($parent, &$nodes)
|
|
|
1078 |
{
|
|
|
1079 |
$noChildren = !$this->hasChildren($nodes);
|
|
|
1080 |
$childs = array();
|
|
|
1081 |
for(reset($nodes); $key = key($nodes);)
|
|
|
1082 |
{
|
|
|
1083 |
next($nodes);
|
|
|
1084 |
if($noChildren)
|
|
|
1085 |
{
|
|
|
1086 |
$childs[] = $key;
|
|
|
1087 |
unset($nodes[$key]);
|
|
|
1088 |
}
|
|
|
1089 |
else
|
|
|
1090 |
$this->collectChildren($key, $nodes[$key]);
|
|
|
1091 |
}
|
|
|
1092 |
if(count($childs) > 0)
|
|
|
1093 |
$this->onChildNodesVisited($parent, $childs);
|
|
|
1094 |
}
|
|
|
1095 |
|
|
|
1096 |
/**
|
|
|
1097 |
* Set the object properties for all the child nodes visited.
|
|
|
1098 |
* @param string parent node id
|
|
|
1099 |
* @param array list of child nodes visited.
|
|
|
1100 |
*/
|
|
|
1101 |
protected function onChildNodesVisited($parent, $nodes)
|
|
|
1102 |
{
|
|
|
1103 |
if(empty($parent) || empty($this->_entries[$parent]))
|
|
|
1104 |
return;
|
|
|
1105 |
|
|
|
1106 |
$parentObject = $this->_entries[$parent]['object'];
|
|
|
1107 |
$property = $this->_entries[$nodes[0]]['property'];
|
|
|
1108 |
|
|
|
1109 |
$list = TPropertyAccess::get($parentObject, $property);
|
|
|
1110 |
|
|
|
1111 |
foreach($nodes as $node)
|
|
|
1112 |
{
|
|
|
1113 |
if($list instanceof TList)
|
|
|
1114 |
$parentObject->{$property}[] = $this->_entries[$node]['object'];
|
|
|
1115 |
else if(is_array($list))
|
|
|
1116 |
$list[] = $this->_entries[$node]['object'];
|
|
|
1117 |
else
|
|
|
1118 |
throw new TSqlMapExecutionException(
|
|
|
1119 |
'sqlmap_property_must_be_list');
|
|
|
1120 |
}
|
|
|
1121 |
|
|
|
1122 |
if(is_array($list))
|
|
|
1123 |
TPropertyAccess::set($parentObject, $property, $list);
|
|
|
1124 |
|
|
|
1125 |
if($this->_entries[$parent]['property'] === null)
|
|
|
1126 |
$this->_list[] = $parentObject;
|
|
|
1127 |
}
|
|
|
1128 |
|
|
|
1129 |
/**
|
|
|
1130 |
* @return array object collection.
|
|
|
1131 |
*/
|
|
|
1132 |
protected function getCollection()
|
|
|
1133 |
{
|
|
|
1134 |
return $this->_list;
|
|
|
1135 |
}
|
|
|
1136 |
}
|
|
|
1137 |
|
|
|
1138 |
/**
|
|
|
1139 |
* TResultSetListItemParameter class
|
|
|
1140 |
*
|
|
|
1141 |
* @author Wei Zhuo <weizho[at]gmail[dot]com>
|
|
|
1142 |
* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $
|
|
|
1143 |
* @package System.Data.SqlMap.Statements
|
|
|
1144 |
* @since 3.1
|
|
|
1145 |
*/
|
|
|
1146 |
class TResultSetListItemParameter extends TComponent
|
|
|
1147 |
{
|
|
|
1148 |
private $_resultObject;
|
|
|
1149 |
private $_parameterObject;
|
|
|
1150 |
private $_list;
|
|
|
1151 |
|
|
|
1152 |
public function __construct($result, $parameter, &$list)
|
|
|
1153 |
{
|
|
|
1154 |
$this->_resultObject = $result;
|
|
|
1155 |
$this->_parameterObject = $parameter;
|
|
|
1156 |
$this->_list = &$list;
|
|
|
1157 |
}
|
|
|
1158 |
|
|
|
1159 |
public function getResult()
|
|
|
1160 |
{
|
|
|
1161 |
return $this->_resultObject;
|
|
|
1162 |
}
|
|
|
1163 |
|
|
|
1164 |
public function getParameter()
|
|
|
1165 |
{
|
|
|
1166 |
return $this->_parameterObject;
|
|
|
1167 |
}
|
|
|
1168 |
|
|
|
1169 |
public function &getList()
|
|
|
1170 |
{
|
|
|
1171 |
return $this->_list;
|
|
|
1172 |
}
|
|
|
1173 |
}
|
|
|
1174 |
|
|
|
1175 |
/**
|
|
|
1176 |
* TResultSetMapItemParameter class.
|
|
|
1177 |
*
|
|
|
1178 |
* @author Wei Zhuo <weizho[at]gmail[dot]com>
|
|
|
1179 |
* @version $Id: TMappedStatement.php 2582 2008-12-03 07:36:59Z christophe.boulain $
|
|
|
1180 |
* @package System.Data.SqlMap.Statements
|
|
|
1181 |
* @since 3.1
|
|
|
1182 |
*/
|
|
|
1183 |
class TResultSetMapItemParameter extends TComponent
|
|
|
1184 |
{
|
|
|
1185 |
private $_key;
|
|
|
1186 |
private $_value;
|
|
|
1187 |
private $_parameterObject;
|
|
|
1188 |
private $_map;
|
|
|
1189 |
|
|
|
1190 |
public function __construct($key, $value, $parameter, &$map)
|
|
|
1191 |
{
|
|
|
1192 |
$this->_key = $key;
|
|
|
1193 |
$this->_value = $value;
|
|
|
1194 |
$this->_parameterObject = $parameter;
|
|
|
1195 |
$this->_map = &$map;
|
|
|
1196 |
}
|
|
|
1197 |
|
|
|
1198 |
public function getKey()
|
|
|
1199 |
{
|
|
|
1200 |
return $this->_key;
|
|
|
1201 |
}
|
|
|
1202 |
|
|
|
1203 |
public function getValue()
|
|
|
1204 |
{
|
|
|
1205 |
return $this->_value;
|
|
|
1206 |
}
|
|
|
1207 |
|
|
|
1208 |
public function getParameter()
|
|
|
1209 |
{
|
|
|
1210 |
return $this->_parameterObject;
|
|
|
1211 |
}
|
|
|
1212 |
|
|
|
1213 |
public function &getMap()
|
|
|
1214 |
{
|
|
|
1215 |
return $this->_map;
|
|
|
1216 |
}
|
|
|
1217 |
}
|
|
|
1218 |
|