Source for file BasePeer.php
Documentation is available at BasePeer.php
* $Id: BasePeer.php 821 2007-11-20 12:47:17Z hans $
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://propel.phpdb.org>.
* This is a utility class for all generated Peer classes in the system.
* Peer classes are responsible for isolating all of the database access
* for a specific business object. They execute all of the SQL
* against the database. Over time this class has grown to include
* utility methods which ease execution of cross-database queries and
* the implementation of concrete Peers.
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Kaspars Jaudzems <kaspars.jaudzems@inbox.lv> (Propel)
* @author Frank Y. Kim <frank.kim@clearink.com> (Torque)
* @author John D. McNally <jmcnally@collab.net> (Torque)
* @author Brett McLaughlin <bmclaugh@algx.net> (Torque)
* @author Stephen Haberman <stephenh@chase3000.com> (Torque)
* @version $Revision: 821 $
/** Array (hash) that contains the cached mapBuilders. */
private static $mapBuilders = array();
/** Array (hash) that contains cached validators */
private static $validatorMap = array();
const TYPE_PHPNAME = 'phpName';
const TYPE_STUDLYPHPNAME = 'studlyPhpName';
* column (peer) name type
const TYPE_COLNAME = 'colName';
const TYPE_FIELDNAME = 'fieldName';
* simply the numerical array index, e.g. 4
static public function getFieldnames ($classname, $type = self::TYPE_PHPNAME) {
// TODO we should take care of including the peer class here
$peerclass = 'Base' . $classname . 'Peer'; // TODO is this always true?
$callable = array($peerclass, 'getFieldnames');
// TODO we should take care of including the peer class here
$peerclass = 'Base' . $classname . 'Peer'; // TODO is this always true?
$callable = array($peerclass, 'translateFieldname');
$args = array($fieldname, $fromType, $toType);
* Method to perform deletes based on values and keys in a
* @param Criteria $criteria The criteria to use.
* @param PDO $con A PDO connection object.
* @return int The number of rows affected by last statement execution. For most
* uses there is only one delete statement executed, so this number
* will correspond to the number of rows affected by the call to this
* method. Note that the return value does require that this information
* is returned (supported) by the PDO driver.
* @throws PropelException
public static function doDelete(Criteria $criteria, PDO $con)
// Set up a list of required tables (one DELETE statement will
// be executed per table)
foreach ($criteria as $c) {
foreach ($c->getAllTables() as $tableName) {
$tableName2 = $criteria->getTableForAlias($tableName);
if ($tableName2 !== null) {
$tables_keys[$tableName2 . ' ' . $tableName] = true;
$tables_keys[$tableName] = true;
} // foreach criteria->keys()
$affectedRows = 0; // initialize this in case the next loop has no iterations.
foreach ($tables as $tableName) {
foreach ($dbMap->getTable($tableName)->getColumns() as $colMap) {
$key = $tableName . '.' . $colMap->getColumnName();
if ($criteria->containsKey($key)) {
$criteria->getCriterion($key)->appendPsTo($sb, $selectParams);
if (empty($whereClause)) {
throw new PropelException("Cowardly refusing to delete from table $tableName with empty WHERE clause.");
// Execute the statement.
$sql = "DELETE FROM " . $tableName . " WHERE " . implode(" AND ", $whereClause);
$stmt = $con->prepare($sql);
self::populateStmtValues($stmt, $selectParams, $dbMap, $db);
$affectedRows = $stmt->rowCount();
* Method to deletes all contents of specified table.
* This method is invoked from generated Peer classes like this:
* public static function doDeleteAll($con = null)
* if ($con === null) $con = Propel::getConnection(self::DATABASE_NAME);
* BasePeer::doDeleteAll(self::TABLE_NAME, $con);
* @param string $tableName The name of the table to empty.
* @param PDO $con A PDO connection object.
* @return int The number of rows affected by the statement. Note
* that the return value does require that this information
* is returned (supported) by the Creole db driver.
* @throws PropelException - wrapping SQLException caught from statement execution.
public static function doDeleteAll($tableName, PDO $con)
$sql = "DELETE FROM " . $tableName;
$stmt = $con->prepare($sql);
return $stmt->rowCount();
* Method to perform inserts based on values and keys in a
* If the primary key is auto incremented the data in Criteria
* will be inserted and the auto increment value will be returned.
* If the primary key is included in Criteria then that value will
* be used to insert the row.
* If no primary key is included in Criteria then we will try to
* figure out the primary key from the database map and insert the
* row with the next available id using util.db.IDBroker.
* If no primary key is defined for the table the values will be
* inserted as specified in Criteria and null will be returned.
* @param Criteria $criteria Object containing values to insert.
* @param PDO $con A PDO connection.
* @return mixed The primary key for the new row if (and only if!) the primary key
* is auto-generated. Otherwise will return <code>null</code>.
* @throws PropelException
public static function doInsert(Criteria $criteria, PDO $con) {
// Get the table name and method for determining the primary
$keys = $criteria->keys();
$tableName = $criteria->getTableName( $keys[0] );
throw new PropelException("Database insert attempted without anything specified to insert");
$tableMap = $dbMap->getTable($tableName);
$keyInfo = $tableMap->getPrimaryKeyMethodInfo();
$useIdGen = $tableMap->isUseIdGenerator();
//$keyGen = $con->getIdGenerator();
$pk = self::getPrimaryKey($criteria);
// only get a new key value if you need to
// the reason is that a primary key might be defined
// but you are still going to set its value. for example:
// a join table where both keys are primary and you are
// setting both columns with your own values
// pk will be null if there is no primary key defined for the table
if ($pk !== null && $useIdGen && !$criteria->containsKey($pk->getFullyQualifiedName()) && $db->isGetIdBeforeInsert()) {
$id = $db->getId($con, $keyInfo);
$criteria->add($pk->getFullyQualifiedName(), $id);
$qualifiedCols = $criteria->keys(); // we need table.column cols when populating values
$columns = array(); // but just 'column' cols for the SQL
foreach ($qualifiedCols as $qualifiedCol) {
$columns[] = substr($qualifiedCol, strpos($qualifiedCol, '.') + 1);
if ($adapter->useQuoteIdentifier()) {
$columns = array_map(array($adapter, 'quoteIdentifier'), $columns);
$sql = "INSERT INTO " . $tableName
. " (" . implode(",", $columns) . ")"
$stmt = $con->prepare($sql);
self::populateStmtValues($stmt, self::buildParams($qualifiedCols, $criteria), $dbMap, $db);
// If the primary key column is auto-incremented, get the id now.
if ($pk !== null && $useIdGen && $db->isGetIdAfterInsert()) {
$id = $db->getId($con, $keyInfo);
* Method used to update rows in the DB. Rows are selected based
* on selectCriteria and updated using values in updateValues.
* Use this method for performing an update of the kind:
* WHERE some_column = some value AND could_have_another_column =
* another value AND so on.
* @param $selectCriteria A Criteria object containing values used in where
* @param $updateValues A Criteria object containing values used in set
* @param PDO $con The PDO connection object to use.
* @return int The number of rows affected by last update statement. For most
* uses there is only one update statement executed, so this number
* will correspond to the number of rows affected by the call to this
* method. Note that the return value does require that this information
* is returned (supported) by the Creole db driver.
* @throws PropelException
public static function doUpdate(Criteria $selectCriteria, Criteria $updateValues, PDO $con) {
// Get list of required tables, containing all columns
$tablesColumns = $selectCriteria->getTablesColumns();
// we also need the columns for the update SQL
$updateTablesColumns = $updateValues->getTablesColumns();
$affectedRows = 0; // initialize this in case the next loop has no iterations.
foreach ($tablesColumns as $tableName => $columns) {
foreach ($columns as $colName) {
$selectCriteria->getCriterion($colName)->appendPsTo($sb, $selectParams);
$sql = "UPDATE " . $tableName . " SET ";
foreach ($updateTablesColumns[$tableName] as $col) {
// add identifiers for the actual database?
if ($db->useQuoteIdentifier()) {
$updateColumnName = $db->quoteIdentifier($updateColumnName);
$sql .= $updateColumnName . " = ?,";
$sql = substr($sql, 0, - 1) . " WHERE " . implode(" AND ", $whereClause);
$stmt = $con->prepare($sql);
// Replace '?' with the actual values
self::populateStmtValues($stmt, array_merge(self::buildParams($updateTablesColumns[$tableName], $updateValues), $selectParams), $dbMap, $db);
$affectedRows = $stmt->rowCount();
if ($stmt) $stmt = null; // close
} // foreach table in the criteria
* Executes query build by createSelectSql() and returns ResultSet.
* @param Criteria $criteria A Criteria.
* @param PDO $con A PDO connection to use.
* @return ResultSet The resultset.
* @throws PropelException
public static function doSelect(Criteria $criteria, PDO $con = null)
// Transaction support exists for (only?) Postgres, which must
// have SELECT statements that include bytea columns wrapped w/
if ($criteria->isUseTransaction()) Transaction::begin($con);
$sql = self::createSelectSql($criteria, $params);
$stmt = $con->prepare($sql);
// FIXME - add SQL-modification for LIMIT/OFFSET into DBAdapters & createSelectSql method.
// $stmt->setLimit($criteria->getLimit());
// $stmt->setOffset($criteria->getOffset());
self::populateStmtValues($stmt, $params, $dbMap, $db);
if ($criteria->isUseTransaction()) Transaction::commit($con);
if ($stmt) $stmt = null; // close
if ($criteria->isUseTransaction()) Transaction::rollback($con);
* Populates values in a prepared statement.
* @param PreparedStatement $stmt
* @param array $params array('column' => ..., 'table' => ..., 'value' => ...)
* @param DatabaseMap $dbMap
* @return int The number of params replaced.
private static function populateStmtValues($stmt, $params, DatabaseMap $dbMap, DBAdapter $db)
foreach ($params as $param) {
$tableName = $param['table'];
$columnName = $param['column'];
$value = $param['value'];
$stmt->bindValue($i++ , null, PDO::PARAM_NULL);
$cMap = $dbMap->getTable($tableName)->getColumn($columnName);
$type = $cMap->getType();
$pdoType = $cMap->getPdoType();
// FIXME - This is a temporary hack to get around apparent bugs w/ PDO+MYSQL
// See http://pecl.php.net/bugs/bug.php?id=9919
if ($pdoType == PDO::PARAM_BOOL && $db instanceof DBMySQL) {
$pdoType = PDO::PARAM_INT;
} elseif (is_numeric($value) && $cMap->isEpochTemporal()) { // it's a timestamp that needs to be formatted
$value = date($db->getTimestampFormatter(), $value);
|