1 | <?php |
---|
2 | /* |
---|
3 | * $Id: BasePeer.php 1060 2008-06-13 12:52:23Z hans $ |
---|
4 | * |
---|
5 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
---|
6 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
---|
7 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
---|
8 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
---|
9 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
---|
10 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
---|
11 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
12 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
13 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
14 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
---|
15 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
16 | * |
---|
17 | * This software consists of voluntary contributions made by many individuals |
---|
18 | * and is licensed under the LGPL. For more information please see |
---|
19 | * <http://propel.phpdb.org>. |
---|
20 | */ |
---|
21 | |
---|
22 | /** |
---|
23 | * This is a utility class for all generated Peer classes in the system. |
---|
24 | * |
---|
25 | * Peer classes are responsible for isolating all of the database access |
---|
26 | * for a specific business object. They execute all of the SQL |
---|
27 | * against the database. Over time this class has grown to include |
---|
28 | * utility methods which ease execution of cross-database queries and |
---|
29 | * the implementation of concrete Peers. |
---|
30 | * |
---|
31 | * @author Hans Lellelid <hans@xmpl.org> (Propel) |
---|
32 | * @author Kaspars Jaudzems <kaspars.jaudzems@inbox.lv> (Propel) |
---|
33 | * @author Heltem <heltem@o2php.com> (Propel) |
---|
34 | * @author Frank Y. Kim <frank.kim@clearink.com> (Torque) |
---|
35 | * @author John D. McNally <jmcnally@collab.net> (Torque) |
---|
36 | * @author Brett McLaughlin <bmclaugh@algx.net> (Torque) |
---|
37 | * @author Stephen Haberman <stephenh@chase3000.com> (Torque) |
---|
38 | * @version $Revision: 1060 $ |
---|
39 | * @package propel.util |
---|
40 | */ |
---|
41 | class BasePeer |
---|
42 | { |
---|
43 | |
---|
44 | /** Array (hash) that contains the cached mapBuilders. */ |
---|
45 | private static $mapBuilders = array(); |
---|
46 | |
---|
47 | /** Array (hash) that contains cached validators */ |
---|
48 | private static $validatorMap = array(); |
---|
49 | |
---|
50 | /** |
---|
51 | * phpname type |
---|
52 | * e.g. 'AuthorId' |
---|
53 | */ |
---|
54 | const TYPE_PHPNAME = 'phpName'; |
---|
55 | |
---|
56 | /** |
---|
57 | * studlyphpname type |
---|
58 | * e.g. 'authorId' |
---|
59 | */ |
---|
60 | const TYPE_STUDLYPHPNAME = 'studlyPhpName'; |
---|
61 | |
---|
62 | /** |
---|
63 | * column (peer) name type |
---|
64 | * e.g. 'book.AUTHOR_ID' |
---|
65 | */ |
---|
66 | const TYPE_COLNAME = 'colName'; |
---|
67 | |
---|
68 | /** |
---|
69 | * column fieldname type |
---|
70 | * e.g. 'author_id' |
---|
71 | */ |
---|
72 | const TYPE_FIELDNAME = 'fieldName'; |
---|
73 | |
---|
74 | /** |
---|
75 | * num type |
---|
76 | * simply the numerical array index, e.g. 4 |
---|
77 | */ |
---|
78 | const TYPE_NUM = 'num'; |
---|
79 | |
---|
80 | static public function getFieldnames ($classname, $type = self::TYPE_PHPNAME) { |
---|
81 | |
---|
82 | // TODO we should take care of including the peer class here |
---|
83 | |
---|
84 | $peerclass = 'Base' . $classname . 'Peer'; // TODO is this always true? |
---|
85 | $callable = array($peerclass, 'getFieldnames'); |
---|
86 | $args = array($type); |
---|
87 | |
---|
88 | return call_user_func_array($callable, $args); |
---|
89 | } |
---|
90 | |
---|
91 | static public function translateFieldname($classname, $fieldname, $fromType, $toType) { |
---|
92 | |
---|
93 | // TODO we should take care of including the peer class here |
---|
94 | |
---|
95 | $peerclass = 'Base' . $classname . 'Peer'; // TODO is this always true? |
---|
96 | $callable = array($peerclass, 'translateFieldname'); |
---|
97 | $args = array($fieldname, $fromType, $toType); |
---|
98 | |
---|
99 | return call_user_func_array($callable, $args); |
---|
100 | } |
---|
101 | |
---|
102 | /** |
---|
103 | * Method to perform deletes based on values and keys in a |
---|
104 | * Criteria. |
---|
105 | * |
---|
106 | * @param Criteria $criteria The criteria to use. |
---|
107 | * @param PropelPDO $con A PropelPDO connection object. |
---|
108 | * @return int The number of rows affected by last statement execution. For most |
---|
109 | * uses there is only one delete statement executed, so this number |
---|
110 | * will correspond to the number of rows affected by the call to this |
---|
111 | * method. Note that the return value does require that this information |
---|
112 | * is returned (supported) by the PDO driver. |
---|
113 | * @throws PropelException |
---|
114 | */ |
---|
115 | public static function doDelete(Criteria $criteria, PropelPDO $con) |
---|
116 | { |
---|
117 | $db = Propel::getDB($criteria->getDbName()); |
---|
118 | $dbMap = Propel::getDatabaseMap($criteria->getDbName()); |
---|
119 | |
---|
120 | // Set up a list of required tables (one DELETE statement will |
---|
121 | // be executed per table) |
---|
122 | |
---|
123 | $tables_keys = array(); |
---|
124 | foreach ($criteria as $c) { |
---|
125 | foreach ($c->getAllTables() as $tableName) { |
---|
126 | $tableName2 = $criteria->getTableForAlias($tableName); |
---|
127 | if ($tableName2 !== null) { |
---|
128 | $tables_keys[$tableName2 . ' ' . $tableName] = true; |
---|
129 | } else { |
---|
130 | $tables_keys[$tableName] = true; |
---|
131 | } |
---|
132 | } |
---|
133 | } // foreach criteria->keys() |
---|
134 | |
---|
135 | $affectedRows = 0; // initialize this in case the next loop has no iterations. |
---|
136 | |
---|
137 | $tables = array_keys($tables_keys); |
---|
138 | |
---|
139 | foreach ($tables as $tableName) { |
---|
140 | |
---|
141 | $whereClause = array(); |
---|
142 | $selectParams = array(); |
---|
143 | foreach ($dbMap->getTable($tableName)->getColumns() as $colMap) { |
---|
144 | $key = $tableName . '.' . $colMap->getColumnName(); |
---|
145 | if ($criteria->containsKey($key)) { |
---|
146 | $sb = ""; |
---|
147 | $criteria->getCriterion($key)->appendPsTo($sb, $selectParams); |
---|
148 | $whereClause[] = $sb; |
---|
149 | } |
---|
150 | } |
---|
151 | |
---|
152 | if (empty($whereClause)) { |
---|
153 | throw new PropelException("Cowardly refusing to delete from table $tableName with empty WHERE clause."); |
---|
154 | } |
---|
155 | |
---|
156 | for ($i=0; $i<2; $i++) { |
---|
157 | // Execute the statement. |
---|
158 | try { |
---|
159 | $sql = "DELETE FROM " . $tableName . " WHERE " . implode(" AND ", $whereClause); |
---|
160 | $stmt = $con->prepare($sql); |
---|
161 | self::populateStmtValues($stmt, $selectParams, $dbMap, $db); |
---|
162 | $stmt->execute(); |
---|
163 | $affectedRows = $stmt->rowCount(); |
---|
164 | break; |
---|
165 | } catch (Exception $e) { |
---|
166 | |
---|
167 | if (preg_match('@MySQL server has gone away@', $e->getMessage())) { |
---|
168 | error_log(date('Y-m-d H:i:s').": Mysql delete query failed ($i), requery\n", 3, sfConfig::get('sf_log_dir').'/dblog.txt'); |
---|
169 | Propel::close(); |
---|
170 | Propel::initialize(); |
---|
171 | Propel::initConnection(); |
---|
172 | $con = Propel::getConnection($criteria->getDbName(), Propel::CONNECTION_WRITE); |
---|
173 | continue; |
---|
174 | } |
---|
175 | |
---|
176 | Propel::log($e->getMessage(), Propel::LOG_ERR); |
---|
177 | throw new PropelException("Unable to execute DELETE statement.",$e); |
---|
178 | } |
---|
179 | } |
---|
180 | |
---|
181 | } // for each table |
---|
182 | |
---|
183 | return $affectedRows; |
---|
184 | } |
---|
185 | |
---|
186 | /** |
---|
187 | * Method to deletes all contents of specified table. |
---|
188 | * |
---|
189 | * This method is invoked from generated Peer classes like this: |
---|
190 | * <code> |
---|
191 | * public static function doDeleteAll($con = null) |
---|
192 | * { |
---|
193 | * if ($con === null) $con = Propel::getConnection(self::DATABASE_NAME); |
---|
194 | * BasePeer::doDeleteAll(self::TABLE_NAME, $con); |
---|
195 | * } |
---|
196 | * </code> |
---|
197 | * |
---|
198 | * @param string $tableName The name of the table to empty. |
---|
199 | * @param PropelPDO $con A PropelPDO connection object. |
---|
200 | * @return int The number of rows affected by the statement. Note |
---|
201 | * that the return value does require that this information |
---|
202 | * is returned (supported) by the Creole db driver. |
---|
203 | * @throws PropelException - wrapping SQLException caught from statement execution. |
---|
204 | */ |
---|
205 | public static function doDeleteAll($tableName, PropelPDO $con) |
---|
206 | { |
---|
207 | try { |
---|
208 | $sql = "DELETE FROM " . $tableName; |
---|
209 | $stmt = $con->prepare($sql); |
---|
210 | $stmt->execute(); |
---|
211 | return $stmt->rowCount(); |
---|
212 | } catch (Exception $e) { |
---|
213 | Propel::log($e->getMessage(), Propel::LOG_ERR); |
---|
214 | throw new PropelException("Unable to perform DELETE ALL operation.", $e); |
---|
215 | } |
---|
216 | } |
---|
217 | |
---|
218 | /** |
---|
219 | * Method to perform inserts based on values and keys in a |
---|
220 | * Criteria. |
---|
221 | * <p> |
---|
222 | * If the primary key is auto incremented the data in Criteria |
---|
223 | * will be inserted and the auto increment value will be returned. |
---|
224 | * <p> |
---|
225 | * If the primary key is included in Criteria then that value will |
---|
226 | * be used to insert the row. |
---|
227 | * <p> |
---|
228 | * If no primary key is included in Criteria then we will try to |
---|
229 | * figure out the primary key from the database map and insert the |
---|
230 | * row with the next available id using util.db.IDBroker. |
---|
231 | * <p> |
---|
232 | * If no primary key is defined for the table the values will be |
---|
233 | * inserted as specified in Criteria and null will be returned. |
---|
234 | * |
---|
235 | * @param Criteria $criteria Object containing values to insert. |
---|
236 | * @param PropelPDO $con A PropelPDO connection. |
---|
237 | * @return mixed The primary key for the new row if (and only if!) the primary key |
---|
238 | * is auto-generated. Otherwise will return <code>null</code>. |
---|
239 | * @throws PropelException |
---|
240 | */ |
---|
241 | public static function doInsert(Criteria $criteria, PropelPDO $con) { |
---|
242 | // the primary key |
---|
243 | $id = null; |
---|
244 | |
---|
245 | $db = Propel::getDB($criteria->getDbName()); |
---|
246 | |
---|
247 | // Get the table name and method for determining the primary |
---|
248 | // key value. |
---|
249 | $keys = $criteria->keys(); |
---|
250 | if (!empty($keys)) { |
---|
251 | $tableName = $criteria->getTableName( $keys[0] ); |
---|
252 | } else { |
---|
253 | throw new PropelException("Database insert attempted without anything specified to insert"); |
---|
254 | } |
---|
255 | |
---|
256 | $dbMap = Propel::getDatabaseMap($criteria->getDbName()); |
---|
257 | $tableMap = $dbMap->getTable($tableName); |
---|
258 | $keyInfo = $tableMap->getPrimaryKeyMethodInfo(); |
---|
259 | $useIdGen = $tableMap->isUseIdGenerator(); |
---|
260 | //$keyGen = $con->getIdGenerator(); |
---|
261 | |
---|
262 | $pk = self::getPrimaryKey($criteria); |
---|
263 | |
---|
264 | // only get a new key value if you need to |
---|
265 | // the reason is that a primary key might be defined |
---|
266 | // but you are still going to set its value. for example: |
---|
267 | // a join table where both keys are primary and you are |
---|
268 | // setting both columns with your own values |
---|
269 | |
---|
270 | // pk will be null if there is no primary key defined for the table |
---|
271 | // we're inserting into. |
---|
272 | if ($pk !== null && $useIdGen && !$criteria->keyContainsValue($pk->getFullyQualifiedName()) && $db->isGetIdBeforeInsert()) { |
---|
273 | try { |
---|
274 | $id = $db->getId($con, $keyInfo); |
---|
275 | } catch (Exception $e) { |
---|
276 | throw new PropelException("Unable to get sequence id.", $e); |
---|
277 | } |
---|
278 | $criteria->add($pk->getFullyQualifiedName(), $id); |
---|
279 | } |
---|
280 | |
---|
281 | for ($i=0; $i<2; $i++) { |
---|
282 | try { |
---|
283 | $adapter = Propel::getDB($criteria->getDBName()); |
---|
284 | |
---|
285 | $qualifiedCols = $criteria->keys(); // we need table.column cols when populating values |
---|
286 | $columns = array(); // but just 'column' cols for the SQL |
---|
287 | foreach ($qualifiedCols as $qualifiedCol) { |
---|
288 | $columns[] = substr($qualifiedCol, strrpos($qualifiedCol, '.') + 1); |
---|
289 | } |
---|
290 | |
---|
291 | // add identifiers |
---|
292 | if ($adapter->useQuoteIdentifier()) { |
---|
293 | $columns = array_map(array($adapter, 'quoteIdentifier'), $columns); |
---|
294 | } |
---|
295 | |
---|
296 | $sql = 'INSERT INTO ' . $tableName |
---|
297 | . ' (' . implode(',', $columns) . ')' |
---|
298 | . ' VALUES ('; |
---|
299 | // . substr(str_repeat("?,", count($columns)), 0, -1) . |
---|
300 | for($p=1, $cnt=count($columns); $p <= $cnt; $p++) { |
---|
301 | $sql .= ':p'.$p; |
---|
302 | if ($p !== $cnt) $sql .= ','; |
---|
303 | } |
---|
304 | $sql .= ')'; |
---|
305 | |
---|
306 | $stmt = $con->prepare($sql); |
---|
307 | self::populateStmtValues($stmt, self::buildParams($qualifiedCols, $criteria), $dbMap, $db); |
---|
308 | $stmt->execute(); |
---|
309 | break; |
---|
310 | |
---|
311 | } catch (Exception $e) { |
---|
312 | |
---|
313 | if (preg_match('@MySQL server has gone away@', $e->getMessage())) { |
---|
314 | error_log(date('Y-m-d H:i:s').": Mysql insert query failed ($i), requery\n", 3, sfConfig::get('sf_log_dir').'/dblog.txt'); |
---|
315 | Propel::close(); |
---|
316 | Propel::initialize(); |
---|
317 | Propel::initConnection(); |
---|
318 | $con = Propel::getConnection($criteria->getDbName(), Propel::CONNECTION_WRITE); |
---|
319 | continue; |
---|
320 | } |
---|
321 | |
---|
322 | Propel::log($e->getMessage(), Propel::LOG_ERR); |
---|
323 | throw new PropelException("Unable to execute INSERT statement.", $e); |
---|
324 | } |
---|
325 | } |
---|
326 | |
---|
327 | // If the primary key column is auto-incremented, get the id now. |
---|
328 | if ($pk !== null && $useIdGen && $db->isGetIdAfterInsert()) { |
---|
329 | try { |
---|
330 | $id = $db->getId($con, $keyInfo); |
---|
331 | } catch (Exception $e) { |
---|
332 | throw new PropelException("Unable to get autoincrement id.", $e); |
---|
333 | } |
---|
334 | } |
---|
335 | |
---|
336 | return $id; |
---|
337 | } |
---|
338 | |
---|
339 | public static $low_priority = false; |
---|
340 | /** |
---|
341 | * Method used to update rows in the DB. Rows are selected based |
---|
342 | * on selectCriteria and updated using values in updateValues. |
---|
343 | * <p> |
---|
344 | * Use this method for performing an update of the kind: |
---|
345 | * <p> |
---|
346 | * WHERE some_column = some value AND could_have_another_column = |
---|
347 | * another value AND so on. |
---|
348 | * |
---|
349 | * @param $selectCriteria A Criteria object containing values used in where |
---|
350 | * clause. |
---|
351 | * @param $updateValues A Criteria object containing values used in set |
---|
352 | * clause. |
---|
353 | * @param PropelPDO $con The PropelPDO connection object to use. |
---|
354 | * @return int The number of rows affected by last update statement. For most |
---|
355 | * uses there is only one update statement executed, so this number |
---|
356 | * will correspond to the number of rows affected by the call to this |
---|
357 | * method. Note that the return value does require that this information |
---|
358 | * is returned (supported) by the Creole db driver. |
---|
359 | * @throws PropelException |
---|
360 | */ |
---|
361 | public static function doUpdate(Criteria $selectCriteria, Criteria $updateValues, PropelPDO $con) { |
---|
362 | |
---|
363 | $db = Propel::getDB($selectCriteria->getDbName()); |
---|
364 | $dbMap = Propel::getDatabaseMap($selectCriteria->getDbName()); |
---|
365 | |
---|
366 | // Get list of required tables, containing all columns |
---|
367 | $tablesColumns = $selectCriteria->getTablesColumns(); |
---|
368 | |
---|
369 | // we also need the columns for the update SQL |
---|
370 | $updateTablesColumns = $updateValues->getTablesColumns(); |
---|
371 | |
---|
372 | $affectedRows = 0; // initialize this in case the next loop has no iterations. |
---|
373 | |
---|
374 | foreach ($tablesColumns as $tableName => $columns) { |
---|
375 | |
---|
376 | $whereClause = array(); |
---|
377 | |
---|
378 | $params = array(); |
---|
379 | |
---|
380 | $stmt = null; |
---|
381 | for ($i=0; $i<2; $i++) { |
---|
382 | try { |
---|
383 | |
---|
384 | /*if (self::$low_priority) |
---|
385 | $sql = "UPDATE LOW_PRIORITY " . $tableName . " SET "; |
---|
386 | else*/ |
---|
387 | $sql = "UPDATE " . $tableName . " SET "; |
---|
388 | $p = 1; |
---|
389 | foreach ($updateTablesColumns[$tableName] as $col) { |
---|
390 | $updateColumnName = substr($col, strrpos($col, '.') + 1); |
---|
391 | // add identifiers for the actual database? |
---|
392 | if ($db->useQuoteIdentifier()) { |
---|
393 | $updateColumnName = $db->quoteIdentifier($updateColumnName); |
---|
394 | } |
---|
395 | if ($updateValues->getComparison($col) != Criteria::CUSTOM_EQUAL) { |
---|
396 | $sql .= $updateColumnName . '=:p'.$p++.', '; |
---|
397 | } else { |
---|
398 | $param = $updateValues->get($col); |
---|
399 | $sql .= $updateColumnName . ' = '; |
---|
400 | if (is_array($param)) { |
---|
401 | if (isset($param['raw'])) { |
---|
402 | $raw = $param['raw']; |
---|
403 | $rawcvt = ''; |
---|
404 | // parse the $params['raw'] for ? chars |
---|
405 | for($r=0,$len=strlen($raw); $r < $len; $r++) { |
---|
406 | if ($raw{$r} == '?') { |
---|
407 | $rawcvt .= ':p'.$p++; |
---|
408 | } else { |
---|
409 | $rawcvt .= $raw{$r}; |
---|
410 | } |
---|
411 | } |
---|
412 | $sql .= $rawcvt . ', '; |
---|
413 | } else { |
---|
414 | $sql .= ':p'.$p++.', '; |
---|
415 | } |
---|
416 | if (isset($param['value'])) { |
---|
417 | $updateValues->put($col, $param['value']); |
---|
418 | } |
---|
419 | } else { |
---|
420 | $updateValues->remove($col); |
---|
421 | $sql .= $param . ', '; |
---|
422 | } |
---|
423 | } |
---|
424 | } |
---|
425 | |
---|
426 | $params = self::buildParams($updateTablesColumns[$tableName], $updateValues); |
---|
427 | |
---|
428 | foreach ($columns as $colName) { |
---|
429 | $sb = ""; |
---|
430 | $selectCriteria->getCriterion($colName)->appendPsTo($sb, $params); |
---|
431 | $whereClause[] = $sb; |
---|
432 | } |
---|
433 | |
---|
434 | $sql = substr($sql, 0, -2) . " WHERE " . implode(" AND ", $whereClause); |
---|
435 | |
---|
436 | $stmt = $con->prepare($sql); |
---|
437 | |
---|
438 | // Replace ':p?' with the actual values |
---|
439 | self::populateStmtValues($stmt, $params, $dbMap, $db); |
---|
440 | |
---|
441 | $stmt->execute(); |
---|
442 | |
---|
443 | $affectedRows = $stmt->rowCount(); |
---|
444 | |
---|
445 | $stmt = null; // close |
---|
446 | break; |
---|
447 | |
---|
448 | } catch (Exception $e) { |
---|
449 | if ($stmt) $stmt = null; // close |
---|
450 | |
---|
451 | if (preg_match('@MySQL server has gone away@', $e->getMessage())) { |
---|
452 | error_log(date('Y-m-d H:i:s').": Mysql update query failed ($i), requery\n", 3, sfConfig::get('sf_log_dir').'/dblog.txt'); |
---|
453 | Propel::close(); |
---|
454 | Propel::initialize(); |
---|
455 | Propel::initConnection(); |
---|
456 | $con = Propel::getConnection($criteria->getDbName(), Propel::CONNECTION_WRITE); |
---|
457 | continue; |
---|
458 | } |
---|
459 | |
---|
460 | Propel::log($e->getMessage(), Propel::LOG_ERR); |
---|
461 | throw new PropelException("Unable to execute UPDATE statement.", $e); |
---|
462 | } |
---|
463 | } // for |
---|
464 | |
---|
465 | } // foreach table in the criteria |
---|
466 | |
---|
467 | return $affectedRows; |
---|
468 | } |
---|
469 | |
---|
470 | /** |
---|
471 | * Executes query build by createSelectSql() and returns the resultset statement. |
---|
472 | * |
---|
473 | * @param Criteria $criteria A Criteria. |
---|
474 | * @param PropelPDO $con A PropelPDO connection to use. |
---|
475 | * @return PDOStatement The resultset. |
---|
476 | * @throws PropelException |
---|
477 | * @see createSelectSql() |
---|
478 | */ |
---|
479 | public static function doSelect(Criteria $criteria, PropelPDO $con = null) |
---|
480 | { |
---|
481 | $dbMap = Propel::getDatabaseMap($criteria->getDbName()); |
---|
482 | $db = Propel::getDB($criteria->getDbName()); |
---|
483 | |
---|
484 | if ($con === null) { |
---|
485 | try { |
---|
486 | $con = Propel::getConnection($criteria->getDbName(), Propel::CONNECTION_READ); |
---|
487 | } catch (Exception $e) { |
---|
488 | if (preg_match('@MySQL server has gone away@', $e->getMessage())) { |
---|
489 | error_log(date('Y-m-d H:i:s').": Mysql get connection failed, reconnect\n", 3, sfConfig::get('sf_log_dir').'/dblog.txt'); |
---|
490 | Propel::close(); |
---|
491 | Propel::initialize(); |
---|
492 | Propel::initConnection(); |
---|
493 | $con = Propel::getConnection($criteria->getDbName(), Propel::CONNECTION_READ); |
---|
494 | } |
---|
495 | } |
---|
496 | } |
---|
497 | |
---|
498 | $stmt = null; |
---|
499 | |
---|
500 | if ($criteria->isUseTransaction()) $con->beginTransaction(); |
---|
501 | |
---|
502 | for ($i=0; $i<2; $i++) { |
---|
503 | try { |
---|
504 | |
---|
505 | $params = array(); |
---|
506 | $sql = self::createSelectSql($criteria, $params); |
---|
507 | |
---|
508 | $stmt = $con->prepare($sql); |
---|
509 | |
---|
510 | self::populateStmtValues($stmt, $params, $dbMap, $db); |
---|
511 | |
---|
512 | $stmt->execute(); |
---|
513 | |
---|
514 | if ($criteria->isUseTransaction()) $con->commit(); |
---|
515 | break; |
---|
516 | |
---|
517 | } catch (Exception $e) { |
---|
518 | if ($stmt) $stmt = null; // close |
---|
519 | if ($criteria->isUseTransaction()) $con->rollBack(); |
---|
520 | if (preg_match('@MySQL server has gone away@', $e->getMessage())) { |
---|
521 | error_log(date('Y-m-d H:i:s').": Mysql select query failed ($i), requery\n", 3, sfConfig::get('sf_log_dir').'/dblog.txt'); |
---|
522 | Propel::close(); |
---|
523 | Propel::initialize(); |
---|
524 | Propel::initConnection(); |
---|
525 | $con = Propel::getConnection($criteria->getDbName(), Propel::CONNECTION_READ); |
---|
526 | if ($criteria->isUseTransaction()) $con->beginTransaction(); |
---|
527 | continue; |
---|
528 | } |
---|
529 | Propel::log($e->getMessage(), Propel::LOG_ERR); |
---|
530 | throw new PropelException($e); |
---|
531 | } |
---|
532 | } |
---|
533 | |
---|
534 | return $stmt; |
---|
535 | } |
---|
536 | |
---|
537 | /** |
---|
538 | * Executes a COUNT query using either a simple SQL rewrite or, for more complex queries, a |
---|
539 | * sub-select of the SQL created by createSelectSql() and returns the statement. |
---|
540 | * |
---|
541 | * @param Criteria $criteria A Criteria. |
---|
542 | * @param PropelPDO $con A PropelPDO connection to use. |
---|
543 | * @return PDOStatement The resultset statement. |
---|
544 | * @throws PropelException |
---|
545 | * @see createSelectSql() |
---|
546 | */ |
---|
547 | public static function doCount(Criteria $criteria, PropelPDO $con = null) |
---|
548 | { |
---|
549 | $dbMap = Propel::getDatabaseMap($criteria->getDbName()); |
---|
550 | $db = Propel::getDB($criteria->getDbName()); |
---|
551 | |
---|
552 | if ($con === null) { |
---|
553 | $con = Propel::getConnection($criteria->getDbName(), Propel::CONNECTION_READ); |
---|
554 | } |
---|
555 | |
---|
556 | $stmt = null; |
---|
557 | |
---|
558 | if ($criteria->isUseTransaction()) $con->beginTransaction(); |
---|
559 | |
---|
560 | $needsComplexCount = ($criteria->getGroupByColumns() || $criteria->getOffset() |
---|
561 | || $criteria->getLimit() || $criteria->getHaving() || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())); |
---|
562 | |
---|
563 | try { |
---|
564 | |
---|
565 | $params = array(); |
---|
566 | |
---|
567 | if ($needsComplexCount) { |
---|
568 | $selectSql = self::createSelectSql($criteria, $params); |
---|
569 | $sql = 'SELECT COUNT(*) FROM (' . $selectSql . ') AS propelmatch4cnt'; |
---|
570 | } else { |
---|
571 | // Replace SELECT columns with COUNT(*) |
---|
572 | $criteria->clearSelectColumns()->addSelectColumn('COUNT(*)'); |
---|
573 | $sql = self::createSelectSql($criteria, $params); |
---|
574 | } |
---|
575 | |
---|
576 | $stmt = $con->prepare($sql); |
---|
577 | self::populateStmtValues($stmt, $params, $dbMap, $db); |
---|
578 | $stmt->execute(); |
---|
579 | |
---|
580 | if ($criteria->isUseTransaction()) $con->commit(); |
---|
581 | |
---|
582 | } catch (Exception $e) { |
---|
583 | if ($stmt) $stmt = null; // close |
---|
584 | if ($criteria->isUseTransaction()) $con->rollBack(); |
---|
585 | Propel::log($e->getMessage(), Propel::LOG_ERR); |
---|
586 | throw new PropelException($e); |
---|
587 | } |
---|
588 | |
---|
589 | return $stmt; |
---|
590 | } |
---|
591 | |
---|
592 | /** |
---|
593 | * Populates values in a prepared statement. |
---|
594 | * |
---|
595 | * This method is designed to work with the createSelectSql() method, which creates |
---|
596 | * both the SELECT SQL statement and populates a passed-in array of parameter |
---|
597 | * values that should be substituted. |
---|
598 | * |
---|
599 | * <code> |
---|
600 | * $params = array(); |
---|
601 | * $sql = BasePeer::createSelectSql($criteria, $params); |
---|
602 | * BasePeer::populateStmtValues($stmt, $params, Propel::getDatabaseMap($critera->getDbName()), Propel::getDB($criteria->getDbName())); |
---|
603 | * </code> |
---|
604 | * |
---|
605 | * @param PDOStatement $stmt |
---|
606 | * @param array $params array('column' => ..., 'table' => ..., 'value' => ...) |
---|
607 | * @param DatabaseMap $dbMap |
---|
608 | * @return int The number of params replaced. |
---|
609 | * @see createSelectSql() |
---|
610 | * @see doSelect() |
---|
611 | */ |
---|
612 | private static function populateStmtValues(PDOStatement $stmt, array $params, DatabaseMap $dbMap, DBAdapter $db) |
---|
613 | { |
---|
614 | $i = 1; |
---|
615 | foreach ($params as $param) { |
---|
616 | $tableName = $param['table']; |
---|
617 | $columnName = $param['column']; |
---|
618 | $value = $param['value']; |
---|
619 | |
---|
620 | if ($value === null) { |
---|
621 | |
---|
622 | $stmt->bindValue(':p'.$i++, null, PDO::PARAM_NULL); |
---|
623 | |
---|
624 | } else { |
---|
625 | |
---|
626 | $cMap = $dbMap->getTable($tableName)->getColumn($columnName); |
---|
627 | $type = $cMap->getType(); |
---|
628 | $pdoType = $cMap->getPdoType(); |
---|
629 | |
---|
630 | // FIXME - This is a temporary hack to get around apparent bugs w/ PDO+MYSQL |
---|
631 | // See http://pecl.php.net/bugs/bug.php?id=9919 |
---|
632 | if ($pdoType == PDO::PARAM_BOOL && $db instanceof DBMySQL) { |
---|
633 | $value = (int) $value; |
---|
634 | $pdoType = PDO::PARAM_INT; |
---|
635 | } elseif (is_numeric($value) && $cMap->isEpochTemporal()) { // it's a timestamp that needs to be formatted |
---|
636 | if ($type == PropelColumnTypes::TIMESTAMP) { |
---|
637 | $value = date($db->getTimestampFormatter(), $value); |
---|
638 | } else if ($type == PropelColumnTypes::DATE) { |
---|
639 | $value = date($db->getDateFormatter(), $value); |
---|
640 | } else if ($type == PropelColumnTypes::TIME) { |
---|
641 | $value = date($db->getTimeFormatter(), $value); |
---|
642 | } |
---|
643 | } elseif ($value instanceof DateTime && $cMap->isTemporal()) { // it's a timestamp that needs to be formatted |
---|
644 | if ($type == PropelColumnTypes::TIMESTAMP || $type == PropelColumnTypes::BU_TIMESTAMP) { |
---|
645 | $value = $value->format($db->getTimestampFormatter()); |
---|
646 | } else if ($type == PropelColumnTypes::DATE || $type == PropelColumnTypes::BU_DATE) { |
---|
647 | $value = $value->format($db->getDateFormatter()); |
---|
648 | } else if ($type == PropelColumnTypes::TIME) { |
---|
649 | $value = $value->format($db->getTimeFormatter()); |
---|
650 | } |
---|
651 | } elseif (is_resource($value) && $cMap->isLob()) { |
---|
652 | // we always need to make sure that the stream is rewound, otherwise nothing will |
---|
653 | // get written to database. |
---|
654 | rewind($value); |
---|
655 | } |
---|
656 | |
---|
657 | $stmt->bindValue(':p'.$i++, $value, $pdoType); |
---|
658 | } |
---|
659 | } // foreach |
---|
660 | } |
---|
661 | |
---|
662 | /** |
---|
663 | * Applies any validators that were defined in the schema to the specified columns. |
---|
664 | * |
---|
665 | * @param string $dbName The name of the database |
---|
666 | * @param string $tableName The name of the table |
---|
667 | * @param array $columns Array of column names as key and column values as value. |
---|
668 | */ |
---|
669 | public static function doValidate($dbName, $tableName, $columns) |
---|
670 | { |
---|
671 | $dbMap = Propel::getDatabaseMap($dbName); |
---|
672 | $tableMap = $dbMap->getTable($tableName); |
---|
673 | $failureMap = array(); // map of ValidationFailed objects |
---|
674 | foreach ($columns as $colName => $colValue) { |
---|
675 | if ($tableMap->containsColumn($colName)) { |
---|
676 | $col = $tableMap->getColumn($colName); |
---|
677 | foreach ($col->getValidators() as $validatorMap) { |
---|
678 | $validator = BasePeer::getValidator($validatorMap->getClass()); |
---|
679 | if ($validator && ($col->isNotNull() || $colValue !== null) && $validator->isValid($validatorMap, $colValue) === false) { |
---|
680 | if (!isset($failureMap[$colName])) { // for now we do one ValidationFailed per column, not per rule |
---|
681 | $failureMap[$colName] = new ValidationFailed($colName, $validatorMap->getMessage(), $validator); |
---|
682 | } |
---|
683 | } |
---|
684 | } |
---|
685 | } |
---|
686 | } |
---|
687 | return (!empty($failureMap) ? $failureMap : true); |
---|
688 | } |
---|
689 | |
---|
690 | /** |
---|
691 | * Helper method which returns the primary key contained |
---|
692 | * in the given Criteria object. |
---|
693 | * |
---|
694 | * @param Criteria $criteria A Criteria. |
---|
695 | * @return ColumnMap If the Criteria object contains a primary |
---|
696 | * key, or null if it doesn't. |
---|
697 | * @throws PropelException |
---|
698 | */ |
---|
699 | private static function getPrimaryKey(Criteria $criteria) |
---|
700 | { |
---|
701 | // Assume all the keys are for the same table. |
---|
702 | $keys = $criteria->keys(); |
---|
703 | $key = $keys[0]; |
---|
704 | $table = $criteria->getTableName($key); |
---|
705 | |
---|
706 | $pk = null; |
---|
707 | |
---|
708 | if (!empty($table)) { |
---|
709 | |
---|
710 | $dbMap = Propel::getDatabaseMap($criteria->getDbName()); |
---|
711 | |
---|
712 | if ($dbMap === null) { |
---|
713 | throw new PropelException("\$dbMap is null"); |
---|
714 | } |
---|
715 | |
---|
716 | if ($dbMap->getTable($table) === null) { |
---|
717 | throw new PropelException("\$dbMap->getTable() is null"); |
---|
718 | } |
---|
719 | |
---|
720 | $columns = $dbMap->getTable($table)->getColumns(); |
---|
721 | foreach (array_keys($columns) as $key) { |
---|
722 | if ($columns[$key]->isPrimaryKey()) { |
---|
723 | $pk = $columns[$key]; |
---|
724 | break; |
---|
725 | } |
---|
726 | } |
---|
727 | } |
---|
728 | return $pk; |
---|
729 | } |
---|
730 | |
---|
731 | /** |
---|
732 | * Method to create an SQL query based on values in a Criteria. |
---|
733 | * |
---|
734 | * This method creates only prepared statement SQL (using ? where values |
---|
735 | * will go). The second parameter ($params) stores the values that need |
---|
736 | * to be set before the statement is executed. The reason we do it this way |
---|
737 | * is to let the PDO layer handle all escaping & value formatting. |
---|
738 | * |
---|
739 | * @param Criteria $criteria Criteria for the SELECT query. |
---|
740 | * @param array &$params Parameters that are to be replaced in prepared statement. |
---|
741 | * @return string |
---|
742 | * @throws PropelException Trouble creating the query string. |
---|
743 | */ |
---|
744 | public static function createSelectSql(Criteria $criteria, &$params) { |
---|
745 | |
---|
746 | $db = Propel::getDB($criteria->getDbName()); |
---|
747 | $dbMap = Propel::getDatabaseMap($criteria->getDbName()); |
---|
748 | |
---|
749 | // redundant definition $selectModifiers = array(); |
---|
750 | $selectClause = array(); |
---|
751 | $fromClause = array(); |
---|
752 | $joinClause = array(); |
---|
753 | $joinTables = array(); |
---|
754 | $whereClause = array(); |
---|
755 | $orderByClause = array(); |
---|
756 | // redundant definition $groupByClause = array(); |
---|
757 | |
---|
758 | $orderBy = $criteria->getOrderByColumns(); |
---|
759 | $groupBy = $criteria->getGroupByColumns(); |
---|
760 | $ignoreCase = $criteria->isIgnoreCase(); |
---|
761 | $select = $criteria->getSelectColumns(); |
---|
762 | $aliases = $criteria->getAsColumns(); |
---|
763 | |
---|
764 | // simple copy |
---|
765 | $selectModifiers = $criteria->getSelectModifiers(); |
---|
766 | |
---|
767 | // get selected columns |
---|
768 | foreach ($select as $columnName) { |
---|
769 | |
---|
770 | // expect every column to be of "table.column" formation |
---|
771 | // it could be a function: e.g. MAX(books.price) |
---|
772 | |
---|
773 | $tableName = null; |
---|
774 | |
---|
775 | $selectClause[] = $columnName; // the full column name: e.g. MAX(books.price) |
---|
776 | |
---|
777 | $parenPos = strrpos($columnName, '('); |
---|
778 | $dotPos = strrpos($columnName, '.', ($parenPos !== false ? $parenPos : 0)); |
---|
779 | |
---|
780 | // [HL] I think we really only want to worry about adding stuff to |
---|
781 | // the fromClause if this function has a TABLE.COLUMN in it at all. |
---|
782 | // e.g. COUNT(*) should not need this treatment -- or there needs to |
---|
783 | // be special treatment for '*' |
---|
784 | if ($dotPos !== false) { |
---|
785 | |
---|
786 | if ($parenPos === false) { // table.column |
---|
787 | $tableName = substr($columnName, 0, $dotPos); |
---|
788 | } else { // FUNC(table.column) |
---|
789 | $tableName = substr($columnName, $parenPos + 1, $dotPos - ($parenPos + 1)); |
---|
790 | // functions may contain qualifiers so only take the last |
---|
791 | // word as the table name. |
---|
792 | // COUNT(DISTINCT books.price) |
---|
793 | $lastSpace = strpos($tableName, ' '); |
---|
794 | if ($lastSpace !== false) { // COUNT(DISTINCT books.price) |
---|
795 | $tableName = substr($tableName, $lastSpace + 1); |
---|
796 | } |
---|
797 | } |
---|
798 | $tableName2 = $criteria->getTableForAlias($tableName); |
---|
799 | if ($tableName2 !== null) { |
---|
800 | $fromClause[] = $tableName2 . ' ' . $tableName; |
---|
801 | } else { |
---|
802 | $fromClause[] = $tableName; |
---|
803 | } |
---|
804 | |
---|
805 | } // if $dotPost !== null |
---|
806 | } |
---|
807 | |
---|
808 | // set the aliases |
---|
809 | foreach ($aliases as $alias => $col) { |
---|
810 | $selectClause[] = $col . " AS " . $alias; |
---|
811 | } |
---|
812 | |
---|
813 | // set the index hint |
---|
814 | $indexHint = implode(',',$criteria->getIndexes()); |
---|
815 | |
---|
816 | // add the criteria to WHERE clause |
---|
817 | // this will also add the table names to the FROM clause if they are not already |
---|
818 | // invluded via a LEFT JOIN |
---|
819 | foreach ($criteria->keys() as $key) { |
---|
820 | |
---|
821 | $criterion = $criteria->getCriterion($key); |
---|
822 | $someCriteria = $criterion->getAttachedCriterion(); |
---|
823 | $someCriteriaLength = count($someCriteria); |
---|
824 | $table = null; |
---|
825 | for ($i=0; $i < $someCriteriaLength; $i++) { |
---|
826 | $tableName = $someCriteria[$i]->getTable(); |
---|
827 | |
---|
828 | $table = $criteria->getTableForAlias($tableName); |
---|
829 | if ($table !== null) { |
---|
830 | $fromClause[] = $table . ' ' . $tableName; |
---|
831 | } else { |
---|
832 | $fromClause[] = $tableName; |
---|
833 | $table = $tableName; |
---|
834 | } |
---|
835 | |
---|
836 | $ignoreCase = |
---|
837 | (($criteria->isIgnoreCase() |
---|
838 | || $someCriteria[$i]->isIgnoreCase()) |
---|
839 | && (strpos($dbMap->getTable($table)->getColumn($someCriteria[$i]->getColumn())->getType(), "VARCHAR") !== false) |
---|
840 | ); |
---|
841 | |
---|
842 | $someCriteria[$i]->setIgnoreCase($ignoreCase); |
---|
843 | } |
---|
844 | |
---|
845 | $criterion->setDB($db); |
---|
846 | |
---|
847 | $sb = ""; |
---|
848 | $criterion->appendPsTo($sb, $params); |
---|
849 | $whereClause[] = $sb; |
---|
850 | |
---|
851 | } |
---|
852 | |
---|
853 | // handle RIGHT (straight) joins |
---|
854 | // Loop through the joins, |
---|
855 | // joins with a null join type will be added to the FROM clause and the condition added to the WHERE clause. |
---|
856 | // joins of a specified type: the LEFT side will be added to the fromClause and the RIGHT to the joinClause |
---|
857 | // New Code. |
---|
858 | foreach ((array) $criteria->getJoins() as $join) { // we'll only loop if there's actually something here |
---|
859 | |
---|
860 | // The join might have been established using an alias name |
---|
861 | |
---|
862 | $leftTable = $join->getLeftTableName(); |
---|
863 | $leftTableAlias = ''; |
---|
864 | if ($realTable = $criteria->getTableForAlias($leftTable)) { |
---|
865 | $leftTableAlias = " $leftTable"; |
---|
866 | $leftTable = $realTable; |
---|
867 | } |
---|
868 | |
---|
869 | $rightTable = $join->getRightTableName(); |
---|
870 | $rightTableAlias = ''; |
---|
871 | if ($realTable = $criteria->getTableForAlias($rightTable)) { |
---|
872 | $rightTableAlias = " $rightTable"; |
---|
873 | $rightTable = $realTable; |
---|
874 | } |
---|
875 | |
---|
876 | // determine if casing is relevant. |
---|
877 | if ($ignoreCase = $criteria->isIgnoreCase()) { |
---|
878 | $leftColType = $dbMap->getTable($leftTable)->getColumn($join->getLeftColumnName())->getType(); |
---|
879 | $rightColType = $dbMap->getTable($rightTable)->getColumn($join->getRightColumnName())->getType(); |
---|
880 | $ignoreCase = ($leftColType == 'string' || $rightColType == 'string'); |
---|
881 | } |
---|
882 | |
---|
883 | // build the condition |
---|
884 | $left = $join->getLeftColumns(); |
---|
885 | $right = $join->getRightColumns(); |
---|
886 | $condition = ""; |
---|
887 | for ($i = 0; $i < count($left); $i++) { |
---|
888 | if ($ignoreCase) { |
---|
889 | $condition .= $db->ignoreCase($left[$i]) . '=' . $db->ignoreCase($right[$i]); |
---|
890 | } else { |
---|
891 | $condition .= $left[$i] . '=' . $right[$i]; |
---|
892 | } |
---|
893 | if ($i + 1 < count($left) ) { |
---|
894 | $condition .= " AND "; |
---|
895 | } |
---|
896 | } |
---|
897 | |
---|
898 | // add 'em to the queues.. |
---|
899 | if ($joinType = $join->getJoinType()) { |
---|
900 | if (!$fromClause) { |
---|
901 | $fromClause[] = $leftTable . $leftTableAlias; |
---|
902 | } |
---|
903 | $joinTables[] = $rightTable . $rightTableAlias; |
---|
904 | $joinClause[] = $join->getJoinType() . ' ' . $rightTable . $rightTableAlias . " ON ($condition)"; |
---|
905 | } else { |
---|
906 | $fromClause[] = $leftTable . $leftTableAlias; |
---|
907 | $fromClause[] = $rightTable . $rightTableAlias; |
---|
908 | $whereClause[] = $condition; |
---|
909 | } |
---|
910 | } |
---|
911 | |
---|
912 | // Unique from clause elements |
---|
913 | $fromClause = array_unique($fromClause); |
---|
914 | |
---|
915 | // tables should not exist in both the from and join clauses |
---|
916 | if ($joinTables && $fromClause) { |
---|
917 | foreach ($fromClause as $fi => $ftable) { |
---|
918 | if (in_array($ftable, $joinTables)) { |
---|
919 | unset($fromClause[$fi]); |
---|
920 | } |
---|
921 | } |
---|
922 | } |
---|
923 | |
---|
924 | // Add the GROUP BY columns |
---|
925 | $groupByClause = $groupBy; |
---|
926 | |
---|
927 | $having = $criteria->getHaving(); |
---|
928 | $havingString = null; |
---|
929 | if ($having !== null) { |
---|
930 | $sb = ""; |
---|
931 | $having->appendPsTo($sb, $params); |
---|
932 | $havingString = $sb; |
---|
933 | } |
---|
934 | |
---|
935 | if (!empty($orderBy)) { |
---|
936 | |
---|
937 | foreach ($orderBy as $orderByColumn) { |
---|
938 | |
---|
939 | // Add function expression as-is. |
---|
940 | |
---|
941 | if (strpos($orderByColumn, '(') !== false) { |
---|
942 | $orderByClause[] = $orderByColumn; |
---|
943 | continue; |
---|
944 | } |
---|
945 | |
---|
946 | // Split orderByColumn (i.e. "table.column DESC") |
---|
947 | |
---|
948 | $dotPos = strrpos($orderByColumn, '.'); |
---|
949 | |
---|
950 | if ($dotPos !== false) { |
---|
951 | $tableName = substr($orderByColumn, 0, $dotPos); |
---|
952 | $columnName = substr($orderByColumn, $dotPos+1); |
---|
953 | } |
---|
954 | else { |
---|
955 | $tableName = ''; |
---|
956 | $columnName = $orderByColumn; |
---|
957 | } |
---|
958 | |
---|
959 | $spacePos = strpos($columnName, ' '); |
---|
960 | |
---|
961 | if ($spacePos !== false) { |
---|
962 | $direction = substr($columnName, $spacePos); |
---|
963 | $columnName = substr($columnName, 0, $spacePos); |
---|
964 | } |
---|
965 | else { |
---|
966 | $direction = ''; |
---|
967 | } |
---|
968 | |
---|
969 | $tableAlias = $tableName; |
---|
970 | if ($aliasTableName = $criteria->getTableForAlias($tableName)) { |
---|
971 | $tableName = $aliasTableName; |
---|
972 | } |
---|
973 | |
---|
974 | $columnAlias = $columnName; |
---|
975 | if ($asColumnName = $criteria->getColumnForAs($columnName)) { |
---|
976 | $columnName = $asColumnName; |
---|
977 | } |
---|
978 | |
---|
979 | $column = $tableName ? $dbMap->getTable($tableName)->getColumn($columnName) : null; |
---|
980 | |
---|
981 | if ($criteria->isIgnoreCase() && $column && $column->isText()) { |
---|
982 | $orderByClause[] = $db->ignoreCaseInOrderBy("$tableAlias.$columnAlias") . $direction; |
---|
983 | $selectClause[] = $db->ignoreCaseInOrderBy("$tableAlias.$columnAlias"); |
---|
984 | } else { |
---|
985 | $orderByClause[] = $orderByColumn; |
---|
986 | } |
---|
987 | } |
---|
988 | } |
---|
989 | |
---|
990 | if (empty($fromClause) && $criteria->getPrimaryTableName()) { |
---|
991 | $fromClause[] = $criteria->getPrimaryTableName(); |
---|
992 | } |
---|
993 | |
---|
994 | // from / join tables quoten if it is necessary |
---|
995 | if ($db->useQuoteIdentifier()) { |
---|
996 | $fromClause = array_map(array($db, 'quoteIdentifierTable'), $fromClause); |
---|
997 | $joinClause = $joinClause ? $joinClause : array_map(array($db, 'quoteIdentifierTable'), $joinClause); |
---|
998 | } |
---|
999 | |
---|
1000 | // build from-clause |
---|
1001 | $from = ''; |
---|
1002 | if (!empty($joinClause) && count($fromClause) > 1) { |
---|
1003 | $from .= implode(" CROSS JOIN ", $fromClause); |
---|
1004 | } else { |
---|
1005 | $from .= implode(", ", $fromClause); |
---|
1006 | } |
---|
1007 | |
---|
1008 | $from .= $joinClause ? ' ' . implode(' ', $joinClause) : ''; |
---|
1009 | |
---|
1010 | // Build the SQL from the arrays we compiled |
---|
1011 | $sql = "SELECT " |
---|
1012 | .($selectModifiers ? implode(" ", $selectModifiers) . " " : "") |
---|
1013 | .implode(", ", $selectClause) |
---|
1014 | ." FROM " . $from |
---|
1015 | .($indexHint ? " USE INDEX (".$indexHint.")" : "") |
---|
1016 | .($whereClause ? " WHERE ".implode(" AND ", $whereClause) : "") |
---|
1017 | .($groupByClause ? " GROUP BY ".implode(",", $groupByClause) : "") |
---|
1018 | .($havingString ? " HAVING ".$havingString : "") |
---|
1019 | .($orderByClause ? " ORDER BY ".implode(",", $orderByClause) : ""); |
---|
1020 | |
---|
1021 | // APPLY OFFSET & LIMIT to the query. |
---|
1022 | if ($criteria->getLimit() || $criteria->getOffset()) { |
---|
1023 | $db->applyLimit($sql, $criteria->getOffset(), $criteria->getLimit()); |
---|
1024 | } |
---|
1025 | |
---|
1026 | return $sql; |
---|
1027 | |
---|
1028 | } |
---|
1029 | |
---|
1030 | /** |
---|
1031 | * Builds a params array, like the kind populated by Criterion::appendPsTo(). |
---|
1032 | * This is useful for building an array even when it is not using the appendPsTo() method. |
---|
1033 | * @param array $columns |
---|
1034 | * @param Criteria $values |
---|
1035 | * @return array params array('column' => ..., 'table' => ..., 'value' => ...) |
---|
1036 | */ |
---|
1037 | private static function buildParams($columns, Criteria $values) { |
---|
1038 | $params = array(); |
---|
1039 | foreach ($columns as $key) { |
---|
1040 | if ($values->containsKey($key)) { |
---|
1041 | $crit = $values->getCriterion($key); |
---|
1042 | $params[] = array('column' => $crit->getColumn(), 'table' => $crit->getTable(), 'value' => $crit->getValue()); |
---|
1043 | } |
---|
1044 | } |
---|
1045 | return $params; |
---|
1046 | } |
---|
1047 | |
---|
1048 | /** |
---|
1049 | * This function searches for the given validator $name under propel/validator/$name.php, |
---|
1050 | * imports and caches it. |
---|
1051 | * |
---|
1052 | * @param string $classname The dot-path name of class (e.g. myapp.propel.MyValidator) |
---|
1053 | * @return Validator object or null if not able to instantiate validator class (and error will be logged in this case) |
---|
1054 | */ |
---|
1055 | public static function getValidator($classname) |
---|
1056 | { |
---|
1057 | try { |
---|
1058 | $v = isset(self::$validatorMap[$classname]) ? self::$validatorMap[$classname] : null; |
---|
1059 | if ($v === null) { |
---|
1060 | $cls = Propel::importClass($classname); |
---|
1061 | $v = new $cls(); |
---|
1062 | self::$validatorMap[$classname] = $v; |
---|
1063 | } |
---|
1064 | return $v; |
---|
1065 | } catch (Exception $e) { |
---|
1066 | Propel::log("BasePeer::getValidator(): failed trying to instantiate " . $classname . ": ".$e->getMessage(), Propel::LOG_ERR); |
---|
1067 | } |
---|
1068 | } |
---|
1069 | |
---|
1070 | } |
---|