source: pro-violet-viettel/sourcecode/api.violet.vn/www/plugins/sfPropel13Plugin/lib/vendor/propel/util/BasePeer.php

Last change on this file was 289, checked in by dungnv, 11 years ago
File size: 35.0 KB
Line 
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 */
41class 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}
Note: See TracBrowser for help on using the repository browser.