[ Index ] |
|
Code source de Symfony 1.0.0 |
1 <?php 2 /* 3 * $Id: BasePeer.php 431 2006-08-21 14:06:10Z 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 include_once 'propel/adapter/DBAdapter.php'; 23 include_once 'propel/map/ColumnMap.php'; 24 include_once 'propel/map/DatabaseMap.php'; 25 include_once 'propel/map/MapBuilder.php'; 26 include_once 'propel/map/TableMap.php'; 27 include_once 'propel/map/ValidatorMap.php'; 28 include_once 'propel/validator/ValidationFailed.php'; 29 30 /** 31 * This is a utility class for all generated Peer classes in the system. 32 * 33 * Peer classes are responsible for isolating all of the database access 34 * for a specific business object. They execute all of the SQL 35 * against the database. Over time this class has grown to include 36 * utility methods which ease execution of cross-database queries and 37 * the implementation of concrete Peers. 38 * 39 * @author Hans Lellelid <hans@xmpl.org> (Propel) 40 * @author Kaspars Jaudzems <kaspars.jaudzems@inbox.lv> (Propel) 41 * @author Frank Y. Kim <frank.kim@clearink.com> (Torque) 42 * @author John D. McNally <jmcnally@collab.net> (Torque) 43 * @author Brett McLaughlin <bmclaugh@algx.net> (Torque) 44 * @author Stephen Haberman <stephenh@chase3000.com> (Torque) 45 * @version $Revision: 431 $ 46 * @package propel.util 47 */ 48 class BasePeer 49 { 50 51 /** Array (hash) that contains the cached mapBuilders. */ 52 private static $mapBuilders = array(); 53 54 /** Array (hash) that contains cached validators */ 55 private static $validatorMap = array(); 56 57 /** 58 * phpname type 59 * e.g. 'AuthorId' 60 */ 61 const TYPE_PHPNAME = 'phpName'; 62 63 /** 64 * column (peer) name type 65 * e.g. 'book.AUTHOR_ID' 66 */ 67 const TYPE_COLNAME = 'colName'; 68 69 /** 70 * column fieldname type 71 * e.g. 'author_id' 72 */ 73 const TYPE_FIELDNAME = 'fieldName'; 74 75 /** 76 * num type 77 * simply the numerical array index, e.g. 4 78 */ 79 const TYPE_NUM = 'num'; 80 81 static public function getFieldnames ($classname, $type = self::TYPE_PHPNAME) { 82 83 // TODO we should take care of including the peer class here 84 85 $peerclass = 'Base' . $classname . 'Peer'; // TODO is this always true? 86 $callable = array($peerclass, 'getFieldnames'); 87 $args = array($type); 88 89 return call_user_func_array($callable, $args); 90 } 91 92 static public function translateFieldname($classname, $fieldname, $fromType, $toType) { 93 94 // TODO we should take care of including the peer class here 95 96 $peerclass = 'Base' . $classname . 'Peer'; // TODO is this always true? 97 $callable = array($peerclass, 'translateFieldname'); 98 $args = array($fieldname, $fromType, $toType); 99 100 return call_user_func_array($callable, $args); 101 } 102 103 /** 104 * Method to perform deletes based on values and keys in a 105 * Criteria. 106 * 107 * @param Criteria $criteria The criteria to use. 108 * @param Connection $con A Connection. 109 * @return int The number of rows affected by last statement execution. For most 110 * uses there is only one delete statement executed, so this number 111 * will correspond to the number of rows affected by the call to this 112 * method. Note that the return value does require that this information 113 * is returned (supported) by the Creole db driver. 114 * @throws PropelException 115 */ 116 public static function doDelete(Criteria $criteria, Connection $con) 117 { 118 $db = Propel::getDB($criteria->getDbName()); 119 $dbMap = Propel::getDatabaseMap($criteria->getDbName()); 120 121 // Set up a list of required tables (one DELETE statement will 122 // be executed per table) 123 124 $tables_keys = array(); 125 foreach($criteria as $c) { 126 foreach($c->getAllTables() as $tableName) { 127 $tableName2 = $criteria->getTableForAlias($tableName); 128 if ($tableName2 !== null) { 129 $tables_keys[$tableName2 . ' ' . $tableName] = true; 130 } else { 131 $tables_keys[$tableName] = true; 132 } 133 } 134 } // foreach criteria->keys() 135 136 $affectedRows = 0; // initialize this in case the next loop has no iterations. 137 138 $tables = array_keys($tables_keys); 139 140 foreach($tables as $tableName) { 141 142 $whereClause = array(); 143 $selectParams = array(); 144 foreach($dbMap->getTable($tableName)->getColumns() as $colMap) { 145 $key = $tableName . '.' . $colMap->getColumnName(); 146 if ($criteria->containsKey($key)) { 147 $sb = ""; 148 $criteria->getCriterion($key)->appendPsTo($sb, $selectParams); 149 $whereClause[] = $sb; 150 } 151 } 152 153 if (empty($whereClause)) { 154 throw new PropelException("Cowardly refusing to delete from table $tableName with empty WHERE clause."); 155 } 156 157 // Execute the statement. 158 try { 159 160 $sqlSnippet = implode(" AND ", $whereClause); 161 162 if ($criteria->isSingleRecord()) { 163 $sql = "SELECT COUNT(*) FROM " . $tableName . " WHERE " . $sqlSnippet; 164 $stmt = $con->prepareStatement($sql); 165 self::populateStmtValues($stmt, $selectParams, $dbMap); 166 $rs = $stmt->executeQuery(ResultSet::FETCHMODE_NUM); 167 $rs->next(); 168 if ($rs->getInt(1) > 1) { 169 $rs->close(); 170 throw new PropelException("Expecting to delete 1 record, but criteria match multiple."); 171 } 172 $rs->close(); 173 } 174 175 $sql = "DELETE FROM " . $tableName . " WHERE " . $sqlSnippet; 176 Propel::log($sql, Propel::LOG_DEBUG); 177 $stmt = $con->prepareStatement($sql); 178 self::populateStmtValues($stmt, $selectParams, $dbMap); 179 $affectedRows = $stmt->executeUpdate(); 180 } catch (Exception $e) { 181 Propel::log($e->getMessage(), Propel::LOG_ERR); 182 throw new PropelException("Unable to execute DELETE statement.",$e); 183 } 184 185 } // for each table 186 187 return $affectedRows; 188 } 189 190 /** 191 * Method to deletes all contents of specified table. 192 * 193 * This method is invoked from generated Peer classes like this: 194 * <code> 195 * public static function doDeleteAll($con = null) 196 * { 197 * if ($con === null) $con = Propel::getConnection(self::DATABASE_NAME); 198 * BasePeer::doDeleteAll(self::TABLE_NAME, $con); 199 * } 200 * </code> 201 * 202 * @param string $tableName The name of the table to empty. 203 * @param Connection $con A Connection. 204 * @return int The number of rows affected by the statement. Note 205 * that the return value does require that this information 206 * is returned (supported) by the Creole db driver. 207 * @throws PropelException - wrapping SQLException caught from statement execution. 208 */ 209 public static function doDeleteAll($tableName, Connection $con) 210 { 211 try { 212 $sql = "DELETE FROM " . $tableName; 213 Propel::log($sql, Propel::LOG_DEBUG); 214 $stmt = $con->prepareStatement($sql); 215 return $stmt->executeUpdate(); 216 } catch (Exception $e) { 217 Propel::log($e->getMessage(), Propel::LOG_ERR); 218 throw new PropelException("Unable to perform DELETE ALL operation.", $e); 219 } 220 } 221 222 /** 223 * Method to perform inserts based on values and keys in a 224 * Criteria. 225 * <p> 226 * If the primary key is auto incremented the data in Criteria 227 * will be inserted and the auto increment value will be returned. 228 * <p> 229 * If the primary key is included in Criteria then that value will 230 * be used to insert the row. 231 * <p> 232 * If no primary key is included in Criteria then we will try to 233 * figure out the primary key from the database map and insert the 234 * row with the next available id using util.db.IDBroker. 235 * <p> 236 * If no primary key is defined for the table the values will be 237 * inserted as specified in Criteria and null will be returned. 238 * 239 * @param Criteria $criteria Object containing values to insert. 240 * @param Connection $con A Connection. 241 * @return mixed The primary key for the new row if (and only if!) the primary key 242 * is auto-generated. Otherwise will return <code>null</code>. 243 * @throws PropelException 244 */ 245 public static function doInsert(Criteria $criteria, Connection $con) { 246 247 // the primary key 248 $id = null; 249 250 // Get the table name and method for determining the primary 251 // key value. 252 $keys = $criteria->keys(); 253 if (!empty($keys)) { 254 $tableName = $criteria->getTableName( $keys[0] ); 255 } else { 256 throw new PropelException("Database insert attempted without anything specified to insert"); 257 } 258 259 $dbMap = Propel::getDatabaseMap($criteria->getDbName()); 260 $tableMap = $dbMap->getTable($tableName); 261 $keyInfo = $tableMap->getPrimaryKeyMethodInfo(); 262 $useIdGen = $tableMap->isUseIdGenerator(); 263 $keyGen = $con->getIdGenerator(); 264 265 $pk = self::getPrimaryKey($criteria); 266 267 // only get a new key value if you need to 268 // the reason is that a primary key might be defined 269 // but you are still going to set its value. for example: 270 // a join table where both keys are primary and you are 271 // setting both columns with your own values 272 273 // pk will be null if there is no primary key defined for the table 274 // we're inserting into. 275 if ($pk !== null && $useIdGen && !$criteria->containsKey($pk->getFullyQualifiedName())) { 276 277 // If the keyMethod is SEQUENCE get the id before the insert. 278 if ($keyGen->isBeforeInsert()) { 279 try { 280 $id = $keyGen->getId($keyInfo); 281 } catch (Exception $e) { 282 throw new PropelException("Unable to get sequence id.", $e); 283 } 284 $criteria->add($pk->getFullyQualifiedName(), $id); 285 } 286 } 287 288 try { 289 290 $qualifiedCols = $criteria->keys(); // we need table.column cols when populating values 291 $columns = array(); // but just 'column' cols for the SQL 292 foreach($qualifiedCols as $qualifiedCol) { 293 $columns[] = substr($qualifiedCol, strpos($qualifiedCol, '.') + 1); 294 } 295 296 $sql = "INSERT INTO " . $tableName 297 . " (" . implode(",", $columns) . ")" 298 . " VALUES (" . substr(str_repeat("?,", count($columns)), 0, -1) . ")"; 299 300 Propel::log($sql, Propel::LOG_DEBUG); 301 302 $stmt = $con->prepareStatement($sql); 303 self::populateStmtValues($stmt, self::buildParams($qualifiedCols, $criteria), $dbMap); 304 $stmt->executeUpdate(); 305 306 } catch (Exception $e) { 307 Propel::log($e->getMessage(), Propel::LOG_ERR); 308 throw new PropelException("Unable to execute INSERT statement.", $e); 309 } 310 311 // If the primary key column is auto-incremented, get the id 312 // now. 313 if ($pk !== null && $useIdGen && $keyGen->isAfterInsert()) { 314 try { 315 $id = $keyGen->getId($keyInfo); 316 } catch (Exception $e) { 317 throw new PropelException("Unable to get autoincrement id.", $e); 318 } 319 } 320 321 return $id; 322 } 323 324 /** 325 * Method used to update rows in the DB. Rows are selected based 326 * on selectCriteria and updated using values in updateValues. 327 * <p> 328 * Use this method for performing an update of the kind: 329 * <p> 330 * WHERE some_column = some value AND could_have_another_column = 331 * another value AND so on. 332 * 333 * @param $selectCriteria A Criteria object containing values used in where 334 * clause. 335 * @param $updateValues A Criteria object containing values used in set 336 * clause. 337 * @param $con The Connection to use. 338 * @return int The number of rows affected by last update statement. For most 339 * uses there is only one update statement executed, so this number 340 * will correspond to the number of rows affected by the call to this 341 * method. Note that the return value does require that this information 342 * is returned (supported) by the Creole db driver. 343 * @throws PropelException 344 */ 345 public static function doUpdate(Criteria $selectCriteria, Criteria $updateValues, Connection $con) { 346 347 $db = Propel::getDB($selectCriteria->getDbName()); 348 $dbMap = Propel::getDatabaseMap($selectCriteria->getDbName()); 349 350 // Get list of required tables, containing all columns 351 $tablesColumns = $selectCriteria->getTablesColumns(); 352 353 // we also need the columns for the update SQL 354 $updateTablesColumns = $updateValues->getTablesColumns(); 355 356 $affectedRows = 0; // initialize this in case the next loop has no iterations. 357 358 foreach($tablesColumns as $tableName => $columns) { 359 360 $whereClause = array(); 361 362 $selectParams = array(); 363 foreach($columns as $colName) { 364 $sb = ""; 365 $selectCriteria->getCriterion($colName)->appendPsTo($sb, $selectParams); 366 $whereClause[] = $sb; 367 } 368 369 $rs = null; 370 $stmt = null; 371 try { 372 373 $sqlSnippet = implode(" AND ", $whereClause); 374 375 if ($selectCriteria->isSingleRecord()) { 376 // Get affected records. 377 $sql = "SELECT COUNT(*) FROM " . $tableName . " WHERE " . $sqlSnippet; 378 $stmt = $con->prepareStatement($sql); 379 self::populateStmtValues($stmt, $selectParams, $dbMap); 380 $rs = $stmt->executeQuery(ResultSet::FETCHMODE_NUM); 381 $rs->next(); 382 if ($rs->getInt(1) > 1) { 383 $rs->close(); 384 throw new PropelException("Expected to update 1 record, multiple matched."); 385 } 386 $rs->close(); 387 } 388 389 $sql = "UPDATE " . $tableName . " SET "; 390 foreach($updateTablesColumns[$tableName] as $col) { 391 $sql .= substr($col, strpos($col, '.') + 1) . " = ?,"; 392 } 393 394 $sql = substr($sql, 0, -1) . " WHERE " . $sqlSnippet; 395 396 Propel::log($sql, Propel::LOG_DEBUG); 397 398 $stmt = $con->prepareStatement($sql); 399 400 // Replace '?' with the actual values 401 self::populateStmtValues($stmt, array_merge(self::buildParams($updateTablesColumns[$tableName], $updateValues), $selectParams), $dbMap); 402 403 $affectedRows = $stmt->executeUpdate(); 404 $stmt->close(); 405 406 } catch (Exception $e) { 407 if ($rs) $rs->close(); 408 if ($stmt) $stmt->close(); 409 Propel::log($e->getMessage(), Propel::LOG_ERR); 410 throw new PropelException("Unable to execute UPDATE statement.", $e); 411 } 412 413 } // foreach table in the criteria 414 415 return $affectedRows; 416 } 417 418 /** 419 * Executes query build by createSelectSql() and returns ResultSet. 420 * 421 * @param Criteria $criteria A Criteria. 422 * @param Connection $con A connection to use. 423 * @return ResultSet The resultset. 424 * @throws PropelException 425 * @see createSelectSql() 426 */ 427 public static function doSelect(Criteria $criteria, $con = null) 428 { 429 $dbMap = Propel::getDatabaseMap($criteria->getDbName()); 430 431 if ($con === null) 432 $con = Propel::getConnection($criteria->getDbName()); 433 434 $stmt = null; 435 436 try { 437 438 // Transaction support exists for (only?) Postgres, which must 439 // have SELECT statements that include bytea columns wrapped w/ 440 // transactions. 441 if ($criteria->isUseTransaction()) $con->begin(); 442 443 $params = array(); 444 $sql = self::createSelectSql($criteria, $params); 445 446 $stmt = $con->prepareStatement($sql); 447 $stmt->setLimit($criteria->getLimit()); 448 $stmt->setOffset($criteria->getOffset()); 449 450 self::populateStmtValues($stmt, $params, $dbMap); 451 452 $rs = $stmt->executeQuery(ResultSet::FETCHMODE_NUM); 453 if ($criteria->isUseTransaction()) $con->commit(); 454 } catch (Exception $e) { 455 if ($stmt) $stmt->close(); 456 if ($criteria->isUseTransaction()) $con->rollback(); 457 Propel::log($e->getMessage(), Propel::LOG_ERR); 458 throw new PropelException($e); 459 } 460 461 return $rs; 462 } 463 464 /** 465 * Applies any validators that were defined in the schema to the specified columns. 466 * 467 * @param string $dbName The name of the database 468 * @param string $tableName The name of the table 469 * @param array $columns Array of column names as key and column values as value. 470 */ 471 public static function doValidate($dbName, $tableName, $columns) 472 { 473 $dbMap = Propel::getDatabaseMap($dbName); 474 $tableMap = $dbMap->getTable($tableName); 475 $failureMap = array(); // map of ValidationFailed objects 476 foreach($columns as $colName => $colValue) { 477 if ($tableMap->containsColumn($colName)) { 478 $col = $tableMap->getColumn($colName); 479 foreach($col->getValidators() as $validatorMap) { 480 $validator = BasePeer::getValidator($validatorMap->getClass()); 481 if($validator && ($col->isNotNull() || $colValue !== null) && $validator->isValid($validatorMap, $colValue) === false) { 482 if (!isset($failureMap[$colName])) { // for now we do one ValidationFailed per column, not per rule 483 $failureMap[$colName] = new ValidationFailed($colName, $validatorMap->getMessage(), $validator); 484 } 485 } 486 } 487 } 488 } 489 return (!empty($failureMap) ? $failureMap : true); 490 } 491 492 /** 493 * Helper method which returns the primary key contained 494 * in the given Criteria object. 495 * 496 * @param Criteria $criteria A Criteria. 497 * @return ColumnMap If the Criteria object contains a primary 498 * key, or null if it doesn't. 499 * @throws PropelException 500 */ 501 private static function getPrimaryKey(Criteria $criteria) 502 { 503 // Assume all the keys are for the same table. 504 $keys = $criteria->keys(); 505 $key = $keys[0]; 506 $table = $criteria->getTableName($key); 507 508 $pk = null; 509 510 if (!empty($table)) { 511 512 $dbMap = Propel::getDatabaseMap($criteria->getDbName()); 513 514 if ($dbMap === null) { 515 throw new PropelException("\$dbMap is null"); 516 } 517 518 if ($dbMap->getTable($table) === null) { 519 throw new PropelException("\$dbMap->getTable() is null"); 520 } 521 522 $columns = $dbMap->getTable($table)->getColumns(); 523 foreach(array_keys($columns) as $key) { 524 if ($columns[$key]->isPrimaryKey()) { 525 $pk = $columns[$key]; 526 break; 527 } 528 } 529 } 530 return $pk; 531 } 532 533 /** 534 * Method to create an SQL query based on values in a Criteria. 535 * 536 * This method creates only prepared statement SQL (using ? where values 537 * will go). The second parameter ($params) stores the values that need 538 * to be set before the statement is executed. The reason we do it this way 539 * is to let the Creole layer handle all escaping & value formatting. 540 * 541 * @param Criteria $criteria Criteria for the SELECT query. 542 * @param array &$params Parameters that are to be replaced in prepared statement. 543 * @return string 544 * @throws PropelException Trouble creating the query string. 545 */ 546 public static function createSelectSql(Criteria $criteria, &$params) { 547 548 $db = Propel::getDB($criteria->getDbName()); 549 $dbMap = Propel::getDatabaseMap($criteria->getDbName()); 550 551 // redundant definition $selectModifiers = array(); 552 $selectClause = array(); 553 $fromClause = array(); 554 $joinClause = array(); 555 $joinTables = array(); 556 $whereClause = array(); 557 $orderByClause = array(); 558 // redundant definition $groupByClause = array(); 559 560 $orderBy = $criteria->getOrderByColumns(); 561 $groupBy = $criteria->getGroupByColumns(); 562 $ignoreCase = $criteria->isIgnoreCase(); 563 $select = $criteria->getSelectColumns(); 564 $aliases = $criteria->getAsColumns(); 565 566 // simple copy 567 $selectModifiers = $criteria->getSelectModifiers(); 568 569 // get selected columns 570 foreach($select as $columnName) { 571 572 // expect every column to be of "table.column" formation 573 // it could be a function: e.g. MAX(books.price) 574 575 $tableName = null; 576 577 $selectClause[] = $columnName; // the full column name: e.g. MAX(books.price) 578 579 $parenPos = strpos($columnName, '('); 580 $dotPos = strpos($columnName, '.'); 581 582 // [HL] I think we really only want to worry about adding stuff to 583 // the fromClause if this function has a TABLE.COLUMN in it at all. 584 // e.g. COUNT(*) should not need this treatment -- or there needs to 585 // be special treatment for '*' 586 if ($dotPos !== false) { 587 588 if ($parenPos === false) { // table.column 589 $tableName = substr($columnName, 0, $dotPos); 590 } else { // FUNC(table.column) 591 $tableName = substr($columnName, $parenPos + 1, $dotPos - ($parenPos + 1)); 592 // functions may contain qualifiers so only take the last 593 // word as the table name. 594 // COUNT(DISTINCT books.price) 595 $lastSpace = strpos($tableName, ' '); 596 if ($lastSpace !== false) { // COUNT(DISTINCT books.price) 597 $tableName = substr($tableName, $lastSpace + 1); 598 } 599 } 600 $tableName2 = $criteria->getTableForAlias($tableName); 601 if ($tableName2 !== null) { 602 $fromClause[] = $tableName2 . ' ' . $tableName; 603 } else { 604 $fromClause[] = $tableName; 605 } 606 607 } // if $dotPost !== null 608 } 609 610 // set the aliases 611 foreach($aliases as $alias => $col) { 612 $selectClause[] = $col . " AS " . $alias; 613 } 614 615 // add the criteria to WHERE clause 616 // this will also add the table names to the FROM clause if they are not already 617 // invluded via a LEFT JOIN 618 foreach($criteria->keys() as $key) { 619 620 $criterion = $criteria->getCriterion($key); 621 $someCriteria = $criterion->getAttachedCriterion(); 622 $someCriteriaLength = count($someCriteria); 623 $table = null; 624 for ($i=0; $i < $someCriteriaLength; $i++) { 625 $tableName = $someCriteria[$i]->getTable(); 626 627 $table = $criteria->getTableForAlias($tableName); 628 if ($table !== null) { 629 $fromClause[] = $table . ' ' . $tableName; 630 } else { 631 $fromClause[] = $tableName; 632 $table = $tableName; 633 } 634 635 $ignoreCase = 636 (($criteria->isIgnoreCase() 637 || $someCriteria[$i]->isIgnoreCase()) 638 && ($dbMap->getTable($table)->getColumn($someCriteria[$i]->getColumn())->getType() == "string" ) 639 ); 640 641 $someCriteria[$i]->setIgnoreCase($ignoreCase); 642 } 643 644 $criterion->setDB($db); 645 646 $sb = ""; 647 $criterion->appendPsTo($sb, $params); 648 $whereClause[] = $sb; 649 650 } 651 652 // handle RIGHT (straight) joins 653 // Loop through the joins, 654 // joins with a null join type will be added to the FROM clause and the condition added to the WHERE clause. 655 // joins of a specified type: the LEFT side will be added to the fromClause and the RIGHT to the joinClause 656 // New Code. 657 foreach ((array) $criteria->getJoins() as $join) { // we'll only loop if there's actually something here 658 659 // The join might have been established using an alias name 660 661 $leftTable = $join->getLeftTableName(); 662 $leftTableAlias = ''; 663 if ($realTable = $criteria->getTableForAlias($leftTable)) { 664 $leftTableAlias = " $leftTable"; 665 $leftTable = $realTable; 666 } 667 668 $rightTable = $join->getRightTableName(); 669 $rightTableAlias = ''; 670 if ($realTable = $criteria->getTableForAlias($rightTable)) { 671 $rightTableAlias = " $rightTable"; 672 $rightTable = $realTable; 673 } 674 675 // determine if casing is relevant. 676 if ($ignoreCase = $criteria->isIgnoreCase()) { 677 $leftColType = $dbMap->getTable($leftTable)->getColumn($join->getLeftColumnName())->getType(); 678 $rightColType = $dbMap->getTable($rightTable)->getColumn($join->getRightColumnName())->getType(); 679 $ignoreCase = ($leftColType == 'string' || $rightColType == 'string'); 680 } 681 682 // build the condition 683 if ($ignoreCase) { 684 $condition = $db->ignoreCase($join->getLeftColumn()) . '=' . $db->ignoreCase($join->getRightColumn()); 685 } else { 686 $condition = $join->getLeftColumn() . '=' . $join->getRightColumn(); 687 } 688 689 // add 'em to the queues.. 690 if ($joinType = $join->getJoinType()) { 691 if (!$fromClause) { 692 $fromClause[] = $leftTable . $leftTableAlias; 693 } 694 $joinTables[] = $rightTable . $rightTableAlias; 695 $joinClause[] = $join->getJoinType() . ' ' . $rightTable . $rightTableAlias . " ON ($condition)"; 696 } else { 697 $fromClause[] = $leftTable . $leftTableAlias; 698 $fromClause[] = $rightTable . $rightTableAlias; 699 $whereClause[] = $condition; 700 } 701 } 702 703 // Unique from clause elements 704 $fromClause = array_unique($fromClause); 705 706 // tables should not exist in both the from and join clauses 707 if ($joinTables && $fromClause) { 708 foreach ($fromClause as $fi => $ftable) { 709 if (in_array($ftable, $joinTables)) { 710 unset($fromClause[$fi]); 711 } 712 } 713 } 714 /* 715 // Old Code. 716 $joins =& $criteria->getJoins(); 717 if (!empty($joins)) { 718 for ($i=0, $joinSize=count($joins); $i < $joinSize; $i++) { 719 $join =& $joins[$i]; 720 $join1 = $join->getLeftColumn(); 721 $join2 = $join->getRightColumn(); 722 723 $tableName = substr($join1, 0, strpos($join1, '.')); 724 $table = $criteria->getTableForAlias($tableName); 725 if ($table !== null) { 726 $fromClause[] = $table . ' ' . $tableName; 727 } else { 728 $fromClause[] = $tableName; 729 } 730 731 $dot = strpos($join2, '.'); 732 $tableName = substr($join2, 0, $dot); 733 $table = $criteria->getTableForAlias($tableName); 734 if ($table !== null) { 735 $fromClause[] = $table . ' ' . $tableName; 736 } else { 737 $fromClause[] = $tableName; 738 $table = $tableName; 739 } 740 $ignoreCase = ($criteria->isIgnoreCase() && ($dbMap->getTable($table)->getColumn(substr($join2, $dot + 1))->getType() == "string")); 741 if ($ignoreCase) { 742 $whereClause[] = $db->ignoreCase($join1) . '=' . $db->ignoreCase($join2); 743 } else { 744 $whereClause[] = $join1 . '=' . $join2; 745 } 746 if ($join->getJoinType()) { 747 $leftTable = $fromClause[count($fromClause) - 2]; 748 $rightTable = $fromClause[count($fromClause) - 1]; 749 $onClause = $whereClause[count($whereClause) - 1]; 750 unset($whereClause[count($whereClause) - 1]); 751 $fromClause [] = $leftTable . ' ' . $join->getJoinType() . ' ' . $rightTable . ' ON ' . $onClause; 752 753 // remove all references to joinTables made by selectColumns, criteriaColumns 754 for ($i = 0, $fromClauseSize=count($fromClause); $i < $fromClauseSize; $i++) { 755 if ($fromClause[$i] == $leftTable || $fromClause[$i] == $rightTable) { 756 unset($fromClause[$i]); 757 } 758 } 759 } // If join type 760 } // Join for loop 761 } // If Joins 762 */ 763 764 // Add the GROUP BY columns 765 $groupByClause = $groupBy; 766 767 $having = $criteria->getHaving(); 768 $havingString = null; 769 if ($having !== null) { 770 $sb = ""; 771 $having->appendPsTo($sb, $params); 772 $havingString = $sb; 773 } 774 775 if (!empty($orderBy)) { 776 777 foreach($orderBy as $orderByColumn) { 778 779 // Add function expression as-is. 780 781 if (strpos($orderByColumn, '(') !== false) { 782 $orderByClause[] = $orderByColumn; 783 continue; 784 } 785 786 // Split orderByColumn (i.e. "table.column DESC") 787 788 $dotPos = strpos($orderByColumn, '.'); 789 790 if ($dotPos !== false) { 791 $tableName = substr($orderByColumn, 0, $dotPos); 792 $columnName = substr($orderByColumn, $dotPos+1); 793 } 794 else { 795 $tableName = ''; 796 $columnName = $orderByColumn; 797 } 798 799 $spacePos = strpos($columnName, ' '); 800 801 if ($spacePos !== false) { 802 $direction = substr($columnName, $spacePos); 803 $columnName = substr($columnName, 0, $spacePos); 804 } 805 else { 806 $direction = ''; 807 } 808 809 $tableAlias = $tableName; 810 if ($aliasTableName = $criteria->getTableForAlias($tableName)) { 811 $tableName = $aliasTableName; 812 } 813 814 $columnAlias = $columnName; 815 if ($asColumnName = $criteria->getColumnForAs($columnName)) { 816 $columnName = $asColumnName; 817 } 818 819 $column = $tableName ? $dbMap->getTable($tableName)->getColumn($columnName) : null; 820 821 if ($column && $column->getType() == 'string') { 822 $orderByClause[] = $db->ignoreCaseInOrderBy("$tableAlias.$columnAlias") . $direction; 823 $selectClause[] = $db->ignoreCaseInOrderBy("$tableAlias.$columnAlias"); 824 } 825 else { 826 $orderByClause[] = $orderByColumn; 827 } 828 } 829 } 830 831 // Build the SQL from the arrays we compiled 832 $sql = "SELECT " 833 .($selectModifiers ? implode(" ", $selectModifiers) . " " : "") 834 .implode(", ", $selectClause) 835 ." FROM ". ( (!empty($joinClause) && count($fromClause) > 1 && (substr(get_class($db), 0, 7) == 'DBMySQL')) ? "(" . implode(", ", $fromClause) . ")" : implode(", ", $fromClause) ) 836 .($joinClause ? ' ' . implode(' ', $joinClause) : '') 837 .($whereClause ? " WHERE ".implode(" AND ", $whereClause) : "") 838 .($groupByClause ? " GROUP BY ".implode(",", $groupByClause) : "") 839 .($havingString ? " HAVING ".$havingString : "") 840 .($orderByClause ? " ORDER BY ".implode(",", $orderByClause) : ""); 841 842 Propel::log($sql . ' [LIMIT: ' . $criteria->getLimit() . ', OFFSET: ' . $criteria->getOffset() . ']', Propel::LOG_DEBUG); 843 844 return $sql; 845 846 } 847 848 /** 849 * Builds a params array, like the kind populated by Criterion::appendPsTo(). 850 * This is useful for building an array even when it is not using the appendPsTo() method. 851 * @param array $columns 852 * @param Criteria $values 853 * @return array params array('column' => ..., 'table' => ..., 'value' => ...) 854 */ 855 private static function buildParams($columns, Criteria $values) { 856 $params = array(); 857 foreach($columns as $key) { 858 if ($values->containsKey($key)) { 859 $crit = $values->getCriterion($key); 860 $params[] = array('column' => $crit->getColumn(), 'table' => $crit->getTable(), 'value' => $crit->getValue()); 861 } 862 } 863 return $params; 864 } 865 866 /** 867 * Populates values in a prepared statement. 868 * 869 * @param PreparedStatement $stmt 870 * @param array $params array('column' => ..., 'table' => ..., 'value' => ...) 871 * @param DatabaseMap $dbMap 872 * @return int The number of params replaced. 873 */ 874 private static function populateStmtValues($stmt, $params, DatabaseMap $dbMap) 875 { 876 $i = 1; 877 foreach($params as $param) { 878 $tableName = $param['table']; 879 $columnName = $param['column']; 880 $value = $param['value']; 881 882 if ($value === null) { 883 $stmt->setNull($i++); 884 } else { 885 $cMap = $dbMap->getTable($tableName)->getColumn($columnName); 886 $setter = 'set' . CreoleTypes::getAffix($cMap->getCreoleType()); 887 $stmt->$setter($i++, $value); 888 } 889 } // foreach 890 } 891 892 /** 893 * This function searches for the given validator $name under propel/validator/$name.php, 894 * imports and caches it. 895 * 896 * @param string $classname The dot-path name of class (e.g. myapp.propel.MyValidator) 897 * @return Validator object or null if not able to instantiate validator class (and error will be logged in this case) 898 */ 899 public static function getValidator($classname) 900 { 901 try { 902 $v = isset(self::$validatorMap[$classname]) ? self::$validatorMap[$classname] : null; 903 if ($v === null) { 904 $cls = Propel::import($classname); 905 $v = new $cls(); 906 self::$validatorMap[$classname] = $v; 907 } 908 return $v; 909 } catch (Exception $e) { 910 Propel::log("BasePeer::getValidator(): failed trying to instantiate " . $classname . ": ".$e->getMessage(), Propel::LOG_ERR); 911 } 912 } 913 914 /** 915 * This method returns the MapBuilder specified in the name 916 * parameter. You should pass in the full dot-path path to the class, ie: 917 * myapp.propel.MyMapMapBuilder. The MapBuilder instances are cached in 918 * this class for speed. 919 * 920 * @param string $classname The dot-path name of class (e.g. myapp.propel.MyMapBuilder) 921 * @return MapBuilder or null (and logs the error) if the MapBuilder was not found. 922 * @todo -cBasePeer Consider adding app-level caching support for map builders. 923 */ 924 public static function getMapBuilder($classname) 925 { 926 try { 927 $mb = isset(self::$mapBuilders[$classname]) ? self::$mapBuilders[$classname] : null; 928 if ($mb === null) { 929 $cls = Propel::import($classname); 930 $mb = new $cls(); 931 self::$mapBuilders[$classname] = $mb; 932 } 933 if (!$mb->isBuilt()) { 934 $mb->doBuild(); 935 } 936 return $mb; 937 } catch (Exception $e) { 938 // Have to catch possible exceptions because method is 939 // used in initialization of Peers. Log the exception and 940 // return null. 941 Propel::log("BasePeer::getMapBuilder() failed trying to instantiate " . $classname . ": " . $e->getMessage(), Propel::LOG_ERR); 942 } 943 } 944 945 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Mar 16 22:42:14 2007 | par Balluche grâce à PHPXref 0.7 |