Overview

Namespaces

  • None
  • Wei
    • Validator

Classes

  • Wei\Validator\All
  • Wei\Validator\AllOf
  • Wei\Validator\Alnum
  • Wei\Validator\Alpha
  • Wei\Validator\BaseValidator
  • Wei\Validator\Between
  • Wei\Validator\Blank
  • Wei\Validator\Callback
  • Wei\Validator\CharLength
  • Wei\Validator\Chinese
  • Wei\Validator\Color
  • Wei\Validator\Contains
  • Wei\Validator\CreditCard
  • Wei\Validator\Date
  • Wei\Validator\DateTime
  • Wei\Validator\Decimal
  • Wei\Validator\Digit
  • Wei\Validator\Dir
  • Wei\Validator\DivisibleBy
  • Wei\Validator\DoubleByte
  • Wei\Validator\Email
  • Wei\Validator\EndsWith
  • Wei\Validator\EqualTo
  • Wei\Validator\Exists
  • Wei\Validator\FieldExists
  • Wei\Validator\File
  • Wei\Validator\GreaterThan
  • Wei\Validator\GreaterThanOrEqual
  • Wei\Validator\IdCardCn
  • Wei\Validator\IdCardHk
  • Wei\Validator\IdCardMo
  • Wei\Validator\IdCardTw
  • Wei\Validator\IdenticalTo
  • Wei\Validator\Image
  • Wei\Validator\In
  • Wei\Validator\Ip
  • Wei\Validator\Length
  • Wei\Validator\LessThan
  • Wei\Validator\LessThanOrEqual
  • Wei\Validator\Lowercase
  • Wei\Validator\Luhn
  • Wei\Validator\MaxLength
  • Wei\Validator\MinLength
  • Wei\Validator\MobileCn
  • Wei\Validator\NaturalNumber
  • Wei\Validator\NoneOf
  • Wei\Validator\Null
  • Wei\Validator\Number
  • Wei\Validator\OneOf
  • Wei\Validator\Password
  • Wei\Validator\Phone
  • Wei\Validator\PhoneCn
  • Wei\Validator\PlateNumberCn
  • Wei\Validator\PositiveInteger
  • Wei\Validator\PostcodeCn
  • Wei\Validator\Present
  • Wei\Validator\QQ
  • Wei\Validator\RecordExists
  • Wei\Validator\Regex
  • Wei\Validator\Required
  • Wei\Validator\SomeOf
  • Wei\Validator\StartsWith
  • Wei\Validator\Time
  • Wei\Validator\Tld
  • Wei\Validator\Type
  • Wei\Validator\Uppercase
  • Wei\Validator\Url
  • Wei\Validator\Uuid
  • Overview
  • Namespace
  • Function
   1: <?php
   2: /**
   3:  * Wei Framework
   4:  *
   5:  * @copyright   Copyright (c) 2008-2015 Twin Huang
   6:  * @license     http://opensource.org/licenses/mit-license.php MIT License
   7:  */
   8: 
   9: namespace Wei;
  10: 
  11: use PDO;
  12: 
  13: /**
  14:  * A database service inspired by Doctrine DBAL
  15:  *
  16:  * @author      Twin Huang <twinhuang@qq.com>
  17:  */
  18: class Db extends Base
  19: {
  20:     /**
  21:      * The name of PDO driver, could be mysql, sqlite or pgsql
  22:      *
  23:      * @var string
  24:      */
  25:     protected $driver = 'mysql';
  26: 
  27:     /**
  28:      * The database username
  29:      *
  30:      * @var string
  31:      */
  32:     protected $user;
  33: 
  34:     /**
  35:      * The database password
  36:      *
  37:      * @var string
  38:      */
  39:     protected $password;
  40: 
  41:     /**
  42:      * The hostname on which the database server resides, for mysql and pgsql
  43:      *
  44:      * @var string
  45:      */
  46:     protected $host = '127.0.0.1';
  47: 
  48:     /**
  49:      * The port on which the database server is running, for mysql and pgsql
  50:      *
  51:      * @var string
  52:      */
  53:     protected $port;
  54: 
  55:     /**
  56:      * The name of the database, for mysql and pgsql
  57:      *
  58:      * @var string
  59:      */
  60:     protected $dbname;
  61: 
  62:     /**
  63:      * The MySQL Unix socket (shouldn't be used with host or port), for mysql only
  64:      *
  65:      * @var string
  66:      */
  67:     protected $unixSocket;
  68: 
  69:     /**
  70:      * The character set, for mysql only
  71:      *
  72:      * @var string
  73:      */
  74:     protected $charset;
  75: 
  76:     /**
  77:      * The path for sqlite database
  78:      *
  79:      * @var string
  80:      */
  81:     protected $path;
  82: 
  83:     /**
  84:      * The dsn parameter for PDO constructor
  85:      *
  86:      * @var string
  87:      */
  88:     protected $dsn;
  89: 
  90:     /**
  91:      * A key=>value array of driver-specific connection attributes
  92:      *
  93:      * @var array
  94:      * @link http://www.php.net/manual/zh/pdo.setattribute.php
  95:      */
  96:     protected $attrs = array();
  97: 
  98:     /**
  99:      * The PDO object
 100:      *
 101:      * @var \PDO
 102:      */
 103:     protected $pdo;
 104: 
 105:     /**
 106:      * The callback triggers before connect to database
 107:      *
 108:      * @var callback
 109:      */
 110:     protected $beforeConnect;
 111: 
 112:     /**
 113:      * The callback triggers when fails to connect to database
 114:      *
 115:      * @var callback
 116:      */
 117:     protected $connectFails;
 118: 
 119:     /**
 120:      * The callback triggers after connect to database
 121:      *
 122:      * @var callback
 123:      */
 124:     protected $afterConnect;
 125: 
 126:     /**
 127:      * The callback triggers before execute query
 128:      *
 129:      * @var callback
 130:      */
 131:     protected $beforeQuery;
 132: 
 133:     /**
 134:      * The callback triggers after execute query
 135:      *
 136:      * @var callback
 137:      */
 138:     protected $afterQuery;
 139: 
 140:     /**
 141:      * Whether connected to the database server
 142:      *
 143:      * @var bool
 144:      */
 145:     protected $isConnected = false;
 146: 
 147:     /**
 148:      * The database table definitions
 149:      *
 150:      * @var array
 151:      */
 152:     protected $tables = array();
 153: 
 154:     /**
 155:      * The base record class when instance a new record object
 156:      *
 157:      * @var string
 158:      */
 159:     protected $recordClass = 'Wei\Record';
 160: 
 161:     /**
 162:      * An associative array that the key is table name and the value is class name
 163:      *
 164:      * @var array
 165:      */
 166:     protected $recordClasses = array();
 167: 
 168:     /**
 169:      * The record namespace without ending "\"
 170:      *
 171:      * @var string
 172:      */
 173:     protected $recordNamespace;
 174: 
 175:     /**
 176:      * The prefix of table name
 177:      *
 178:      * @var string
 179:      */
 180:     protected $tablePrefix;
 181: 
 182:     /**
 183:      * Whether use the options from the default db service
 184:      *
 185:      * @var bool
 186:      */
 187:     protected $global = false;
 188: 
 189:     /**
 190:      * All executed SQL queries
 191:      *
 192:      * @var array
 193:      */
 194:     protected $queries = array();
 195: 
 196:     /**
 197:      * The field names of table
 198:      *
 199:      * @var array
 200:      */
 201:     protected $tableFields = array();
 202: 
 203:     /**
 204:      * The salve db configuration name
 205:      *
 206:      * @var string
 207:      */
 208:     protected $slaveDb;
 209: 
 210:     /**
 211:      * Constructor
 212:      *
 213:      * @param array $options
 214:      */
 215:     public function __construct(array $options = array())
 216:     {
 217:         if (isset($options['global']) && true == $options['global']) {
 218:             $options += (array)$options['wei']->getConfig('db');
 219:         }
 220:         return parent::__construct($options);
 221:     }
 222: 
 223:     /**
 224:      * Create a new instance of a SQL query builder with specified table name
 225:      *
 226:      * @param string $table The name of database table
 227:      * @return Record
 228:      */
 229:     public function __invoke($table = null)
 230:     {
 231:         return $this->init($table);
 232:     }
 233: 
 234:     /**
 235:      * Connect to the database server
 236:      *
 237:      * @throws \PDOException When fails to connect to database server
 238:      * @return boolean
 239:      */
 240:     public function connect()
 241:     {
 242:         if ($this->isConnected) {
 243:             return false;
 244:         }
 245: 
 246:         if (!$this->pdo) {
 247:             $this->beforeConnect && call_user_func($this->beforeConnect, $this);
 248: 
 249:             $dsn = $this->getDsn();
 250:             $attrs = $this->attrs + array(
 251:                 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
 252:                 PDO::ATTR_STRINGIFY_FETCHES => true,
 253:                 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
 254:             );
 255: 
 256:             try {
 257:                 $this->pdo = new PDO($dsn, $this->user, $this->password, $attrs);
 258:             } catch (\PDOException $e) {
 259:                 $this->connectFails && call_user_func($this->connectFails, $this, $e);
 260:                 throw $e;
 261:             }
 262: 
 263:             $this->afterConnect && call_user_func($this->afterConnect, $this, $this->pdo);
 264:         }
 265: 
 266:         $this->isConnected = true;
 267: 
 268:         return true;
 269:     }
 270: 
 271:     /**
 272:      * Check if has connected to the database server
 273:      *
 274:      * @return bool
 275:      */
 276:     public function isConnected()
 277:     {
 278:         return $this->isConnected;
 279:     }
 280: 
 281:     /**
 282:      * Close the database connection
 283:      */
 284:     public function close()
 285:     {
 286:         $this->pdo = null;
 287:         $this->isConnected = false;
 288:     }
 289: 
 290:     /**
 291:      * Close the current connection and create a new one
 292:      */
 293:     public function reconnect()
 294:     {
 295:         $this->close();
 296:         $this->connect();
 297:     }
 298: 
 299:     /**
 300:      * Executes an INSERT query to insert specified data into table
 301:      *
 302:      * @param string $table The name of table
 303:      * @param array $data An associative array containing column-value pairs
 304:      * @return int The number of affected rows
 305:      */
 306:     public function insert($table, array $data)
 307:     {
 308:         $table = $this->getTable($table);
 309:         $field = implode(', ', array_keys($data));
 310: 
 311:         $placeholder = array();
 312:         foreach ($data as $key => $value) {
 313:             if ($value instanceof \stdClass && isset($value->scalar)) {
 314:                 $placeholder[] = $value->scalar;
 315:                 unset($data[$key]);
 316:             } else {
 317:                 $placeholder[] = '?';
 318:             }
 319:         }
 320:         $placeholder = implode(', ', $placeholder);
 321: 
 322:         $query = "INSERT INTO $table ($field) VALUES ($placeholder)";
 323:         return $this->executeUpdate($query, array_values($data));
 324:     }
 325: 
 326:     /**
 327:      * Insert batch data into table
 328:      *
 329:      * @param string $table The name of table
 330:      * @param array $data A two-dimensional array
 331:      * @return int The number of inserted rows
 332:      */
 333:     public function insertBatch($table, array $data)
 334:     {
 335:         $table = $this->getTable($table);
 336:         $field = implode(', ', array_keys($data[0]));
 337:         $placeholders = array();
 338:         $values = array();
 339: 
 340:         switch ($this->driver) {
 341:             default:
 342:             case 'mysql':
 343:             case 'pgsql':
 344:                 foreach ($data as $row) {
 345:                     $placeholders[] = '(' . implode(', ', array_pad(array(), count($row), '?')) . ')';
 346:                     $values = array_merge($values, array_values($row));
 347:                 }
 348:                 $placeholder = 'VALUES ' . implode(', ', $placeholders);
 349:                 break;
 350: 
 351:             // For SQLite before 3.7.11, http://www.sqlite.org/releaselog/3_7_11.html
 352:             case 'sqlite':
 353:                 foreach ($data as $row) {
 354:                     $placeholders[] = 'SELECT ' . implode(', ', array_pad(array(), count($row), '?'));
 355:                     $values = array_merge($values, array_values($row));
 356:                 }
 357:                 $placeholder = implode(' UNION ', $placeholders);
 358:                 break;
 359:         }
 360:         $query = "INSERT INTO $table ($field) $placeholder";
 361:         return $this->executeUpdate($query, $values);
 362:     }
 363: 
 364:     /**
 365:      * Executes a UPDATE query
 366:      *
 367:      * @param string $table The name of table
 368:      * @param array $data An associative array containing column-value pairs
 369:      * @param array $conditions The conditions to search records
 370:      * @return int The number of affected rows
 371:      */
 372:     public function update($table, array $data, array $conditions)
 373:     {
 374:         $table = $this->getTable($table);
 375:         $set = $this->buildSqlObject($data, ', ');
 376:         $where = $this->buildSqlObject($conditions, ' AND ');
 377: 
 378:         $query = "UPDATE $table SET $set WHERE $where";
 379:         $params = array_merge(array_values($data), array_values($conditions));
 380:         return $this->executeUpdate($query, $params);
 381:     }
 382: 
 383:     /**
 384:      * Executes a DELETE query
 385:      *
 386:      * @param string $table The name of table
 387:      * @param array $conditions The conditions to search records
 388:      * @return int The number of affected rows
 389:      */
 390:     public function delete($table, array $conditions)
 391:     {
 392:         $table = $this->getTable($table);
 393:         $where = $this->buildSqlObject($conditions, ' AND ');
 394: 
 395:         $query = "DELETE FROM $table WHERE " . $where;
 396:         return $this->executeUpdate($query, array_values($conditions));
 397:     }
 398: 
 399:     /**
 400:      * Executes a SELECT query and return the first result
 401:      *
 402:      * ```php
 403:      * // Find by the "id" key
 404:      * $db->select('user', 1);
 405:      *
 406:      * // Find by specified column
 407:      * $db->select('user', array('username' => 'twin'));
 408:      *
 409:      * // Find in list
 410:      * $db->select('user', array('id' => array(1, 2, 3)));
 411:      * ```
 412:      *
 413:      * @param string $table The name of table
 414:      * @param string|array $conditions The "id" key value or an associative array containing column-value pairs
 415:      * @param string $select The table columns to select
 416:      * @return array|false An associative array containing column-value pairs
 417:      */
 418:     public function select($table, $conditions, $select = '*')
 419:     {
 420:         $data = $this->selectAll($table, $conditions, $select, 1);
 421:         return $data ? $data[0] : false;
 422:     }
 423: 
 424:     /**
 425:      * Executes a SELECT query and return all results
 426:      *
 427:      * ```php
 428:      * // Find by the "id" key
 429:      * $db->selectAll('user', 1);
 430:      *
 431:      * // Find by specified column
 432:      * $db->selectAll('user', array('username' => 'twin'));
 433:      *
 434:      * // Find in list
 435:      * $db->selectAll('user', array('id' => array(1, 2, 3)));
 436:      * ```
 437:      *
 438:      * @param string $table The name of table
 439:      * @param bool $conditions The "id" key value or an associative array containing column-value pairs
 440:      * @param string $select The table columns to select
 441:      * @param int $limit The row number to retrieve
 442:      * @return array
 443:      */
 444:     public function selectAll($table, $conditions = false, $select = '*', $limit = null)
 445:     {
 446:         $params = array();
 447:         $query = "SELECT $select FROM " . $this->getTable($table) . ' ';
 448: 
 449:         if (is_array($conditions)) {
 450:             if (!empty($conditions)) {
 451:                 $query .= "WHERE " . implode(' = ? AND ', array_keys($conditions)) . ' = ?';
 452:                 $params = array_values($conditions);
 453:             }
 454:         } elseif ($conditions !== false) {
 455:             $query .= "WHERE id = :id";
 456:             $params = array('id' => $conditions);
 457:         }
 458: 
 459:         if ($limit) {
 460:             $query .= " LIMIT $limit";
 461:         }
 462: 
 463:         return $this->query($query, $params)->fetchAll();
 464:     }
 465: 
 466:     /**
 467:      * Executes a query and returns the first array result
 468:      *
 469:      * @param string $sql The SQL query
 470:      * @param mixed $params The query parameters
 471:      * @param array $types The parameter types to bind
 472:      * @return array|false Return an array or false when no result found
 473:      */
 474:     public function fetch($sql, $params = array(), $types = array())
 475:     {
 476:         return $this->query($sql, $params, $types)->fetch();
 477:     }
 478: 
 479:     /**
 480:      * Executes a query and returns all array results
 481:      *
 482:      * @param string $sql The SQL query
 483:      * @param mixed $params The query parameters
 484:      * @param array $types The parameter types to bind
 485:      * @return array|false Return an array or false when no result found
 486:      */
 487:     public function fetchAll($sql, $params = array(), $types = array())
 488:     {
 489:         return $this->query($sql, $params, $types)->fetchAll();
 490:     }
 491: 
 492:     /**
 493:      * Executes a query and returns a column value of the first row
 494:      *
 495:      * @param string $sql The SQL query
 496:      * @param mixed $params The query parameters
 497:      * @param int $column The index of column
 498:      * @return string
 499:      */
 500:     public function fetchColumn($sql, $params = array(), $column = 0)
 501:     {
 502:         return $this->query($sql, $params)->fetchColumn($column);
 503:     }
 504: 
 505:     /**
 506:      * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
 507:      * and returns the number of affected rows
 508:      *
 509:      * @param string $sql The SQL query
 510:      * @param array $params The query parameters
 511:      * @param array $types The parameter types to bind
 512:      * @return int The number of affected rows
 513:      */
 514:     public function executeUpdate($sql, $params = array(), $types = array())
 515:     {
 516:         return $this->query($sql, $params, $types, true);
 517:     }
 518: 
 519:     /**
 520:      * Executes an SQL statement, returning a PDOStatement object or the number of affected rows
 521:      *
 522:      * @param string $sql The SQL query
 523:      * @param array $params The SQL parameters
 524:      * @param array $types The parameter types to bind
 525:      * @param bool $returnRows Whether returns a PDOStatement object or the number of affected rows
 526:      * @throws \PDOException
 527:      * @return \PDOStatement|int
 528:      */
 529:     public function query($sql, $params = array(), $types = array(), $returnRows = false)
 530:     {
 531:         // A select query, using slave db if configured
 532:         if (!$returnRows && $this->slaveDb) {
 533:             /** @var $slaveDb \Wei\Db */
 534:             $slaveDb = $this->wei->get($this->slaveDb);
 535:             return $slaveDb->query($sql, $params, $types, $returnRows);
 536:         }
 537: 
 538:         $this->connect();
 539:         $this->queries[] = $sql;
 540:         if ($this->beforeQuery) {
 541:             call_user_func_array($this->beforeQuery, array($sql, $params, $types, $this));
 542:         }
 543: 
 544:         try {
 545:             if (!$returnRows) {
 546:                 if ($params) {
 547:                     $stmt = $this->pdo->prepare($sql);
 548:                     if ($types) {
 549:                         $this->bindParameter($stmt, $params, $types);
 550:                         $stmt->execute();
 551:                     } else {
 552:                         $stmt->execute((array)$params);
 553:                     }
 554:                 } else {
 555:                     $stmt = $this->pdo->query($sql);
 556:                 }
 557:                 $result = $stmt;
 558:             } else {
 559:                 if ($params) {
 560:                     $stmt = $this->pdo->prepare($sql);
 561:                     $stmt->execute($params);
 562:                     $result = $stmt->rowCount();
 563:                 } else {
 564:                     $result = $this->pdo->exec($sql);
 565:                 }
 566:             }
 567:         } catch (\PDOException $e) {
 568:             // Builder exception message
 569:             $msg = sprintf("An exception occurred while executing \"%s\" : \n\n %s", $sql, $e->getMessage());
 570:             $params && $msg .= ', with parameters ' . json_encode($params);
 571: 
 572:             // Reset exception message
 573:             $message = new \ReflectionProperty($e, 'message');
 574:             $message->setAccessible(true);
 575:             $message->setValue($e, $msg);
 576:             throw $e;
 577:         }
 578: 
 579:         if ($this->afterQuery) {
 580:             call_user_func_array($this->afterQuery, array($sql, $params, $types, $this));
 581:         }
 582: 
 583:         return $result;
 584:     }
 585: 
 586:     /**
 587:      * Returns the rows number of table search by specified parameters
 588:      *
 589:      * @param string $table
 590:      * @param mixed $conditions
 591:      * @return int
 592:      */
 593:     public function count($table, $conditions = false)
 594:     {
 595:         return (int)$this->executeAggregate('COUNT', $table, '1', $conditions);
 596:     }
 597: 
 598:     /**
 599:      * Returns the sum of specified table field and conditions
 600:      *
 601:      * @param string $table
 602:      * @param string $field
 603:      * @param mixed $conditions
 604:      * @return float
 605:      */
 606:     public function sum($table, $field, $conditions = false)
 607:     {
 608:         return $this->executeAggregate('SUM', $table, $field, $conditions);
 609:     }
 610: 
 611:     /**
 612:      * Returns the max value of specified table field and conditions
 613:      *
 614:      * @param string $table
 615:      * @param string $field
 616:      * @param mixed $conditions
 617:      * @return float
 618:      */
 619:     public function max($table, $field, $conditions = false)
 620:     {
 621:         return $this->executeAggregate('MAX', $table, $field, $conditions);
 622:     }
 623: 
 624:     /**
 625:      * Returns the min value of specified table field and conditions
 626:      *
 627:      * @param string $table
 628:      * @param string $field
 629:      * @param mixed $conditions
 630:      * @return float
 631:      */
 632:     public function min($table, $field, $conditions = false)
 633:     {
 634:         return $this->executeAggregate('MIN', $table, $field, $conditions);
 635:     }
 636: 
 637:     /**
 638:      * Returns the avg value of specified table field and conditions
 639:      *
 640:      * @param string $table
 641:      * @param string $field
 642:      * @param mixed $conditions
 643:      * @return float
 644:      */
 645:     public function avg($table, $field, $conditions = false)
 646:     {
 647:         return $this->executeAggregate('AVG', $table, $field, $conditions);
 648:     }
 649: 
 650:     /**
 651:      * Returns the ID of the last inserted row or sequence value
 652:      *
 653:      * @param string $sequence The name of PostgreSQL sequence
 654:      * @return string
 655:      */
 656:     public function lastInsertId($sequence = null)
 657:     {
 658:         return $this->pdo->lastInsertId($sequence);
 659:     }
 660: 
 661:     /**
 662:      * Fetch the SQLSTATE associated with the last operation on the database handle
 663:      *
 664:      * @return mixed
 665:      */
 666:     public function errorCode()
 667:     {
 668:         $this->connect();
 669:         return $this->pdo->errorCode();
 670:     }
 671: 
 672:     /**
 673:      * Fetch extended error information associated with the last operation on the database handle
 674:      *
 675:      * @return array
 676:      */
 677:     public function errorInfo()
 678:     {
 679:         $this->connect();
 680:         return $this->pdo->errorInfo();
 681:     }
 682: 
 683:     /**
 684:      * Init a record instance
 685:      *
 686:      * @param string $table The name of database table
 687:      * @param array $data The data for table record
 688:      * @param bool $isNew Whether it's a new record and have not save to database
 689:      * @return Record
 690:      */
 691:     public function init($table, $data = array(), $isNew = true)
 692:     {
 693:         $class = $this->getRecordClass($table);
 694:         return new $class(array(
 695:             'wei'       => $this->wei,
 696:             'db'        => $this,
 697:             'table'     => $table,
 698:             'isNew'     => $isNew,
 699:             'data'      => $data,
 700:         ));
 701:     }
 702: 
 703:     /**
 704:      * Find a record from specified table and conditions
 705:      *
 706:      * @param string $table The name of table
 707:      * @param string|array $id The primary key value or an associative array containing column-value pairs
 708:      * @return Record|false
 709:      */
 710:     public function find($table, $id)
 711:     {
 712:         $data = $this->select($table, $id);
 713:         return $data ? $this->init($table, $data, false) : false;
 714:     }
 715: 
 716:     /**
 717:      * Find a record from specified table and conditions
 718:      * and throws 404 exception when record not found
 719:      *
 720:      * @param string $table
 721:      * @param string|array $id The primary key value or an associative array containing column-value pairs
 722:      * @return Record
 723:      * @throws \Exception
 724:      */
 725:     public function findOne($table, $id)
 726:     {
 727:         return $this->init($table)->findOne($id);
 728:     }
 729: 
 730:     /**
 731:      * Find a record, if not found, create a new one from specified data
 732:      *
 733:      * @param string $table The name of table
 734:      * @param string $id The primary key value or an associative array containing column-value pairs
 735:      * @param array $data The data to create a new record when record not found
 736:      * @return Record
 737:      */
 738:     public function findOrInit($table, $id, $data = array())
 739:     {
 740:         return $this->init($table)->findOrInit($id, $data);
 741:     }
 742: 
 743:     /**
 744:      * Find records from specified table and conditions
 745:      *
 746:      * @param string $table The name of table
 747:      * @param mixed $where The primary key value or an associative array containing column-value pairs
 748:      * @return Record
 749:      */
 750:     public function findAll($table, $where = false)
 751:     {
 752:         return $this->init($table)->findAll($where);
 753:     }
 754: 
 755:     /**
 756:      * Set the record class for specified table
 757:      *
 758:      * @param string $table
 759:      * @param string $class
 760:      * @return $this
 761:      */
 762:     public function addRecordClass($table, $class)
 763:     {
 764:         $this->recordClasses[$table] = $class;
 765:         return $this;
 766:     }
 767: 
 768:     /**
 769:      * Returns the record class name of table
 770:      *
 771:      * @param string $table The name of table
 772:      * @return string The record class name for table
 773:      */
 774:     public function getRecordClass($table)
 775:     {
 776:         if (isset($this->recordClasses[$table])) {
 777:             return $this->recordClasses[$table];
 778:         }
 779: 
 780:         if ($this->recordNamespace) {
 781:             $class = $this->recordNamespace . '\\' . implode('', array_map('ucfirst', explode('_', $table)));
 782:             if (class_exists($class)) {
 783:                 return $class;
 784:             }
 785:         }
 786: 
 787:         return $this->recordClass;
 788:     }
 789: 
 790:     /**
 791:      * Returns the full table name with prefix
 792:      *
 793:      * @param string $table
 794:      * @return string
 795:      */
 796:     public function getTable($table)
 797:     {
 798:         return $this->tablePrefix . $table;
 799:     }
 800: 
 801:     /**
 802:      * Returns the database username
 803:      *
 804:      * @return string
 805:      */
 806:     public function getUser()
 807:     {
 808:         return $this->user;
 809:     }
 810: 
 811:     /**
 812:      * Returns the database password
 813:      *
 814:      * @return string
 815:      */
 816:     public function getPassword()
 817:     {
 818:         return $this->password;
 819:     }
 820: 
 821:     /**
 822:      * Returns the hostname on which the database server resides
 823:      *
 824:      * @return string
 825:      */
 826:     public function getHost()
 827:     {
 828:         return $this->host;
 829:     }
 830: 
 831:     /**
 832:      * Returns the port on which the database server is running
 833:      *
 834:      * @return string
 835:      */
 836:     public function getPort()
 837:     {
 838:         return $this->port;
 839:     }
 840: 
 841:     /**
 842:      * Returns the name of the database
 843:      *
 844:      * @return string
 845:      */
 846:     public function getDbname()
 847:     {
 848:         return $this->dbname;
 849:     }
 850: 
 851:     /**
 852:      * Returns the name of PDO driver
 853:      *
 854:      * @return string
 855:      */
 856:     public function getDriver()
 857:     {
 858:         return $this->driver;
 859:     }
 860: 
 861:     /**
 862:      * Returns the PDO DSN
 863:      *
 864:      * @return string
 865:      * @throws \RuntimeException When database driver is unsupported
 866:      */
 867:     public function getDsn()
 868:     {
 869:         if ($this->dsn) {
 870:             return $this->dsn;
 871:         }
 872: 
 873:         $dsn = $this->driver . ':';
 874:         switch ($this->driver) {
 875:             case 'mysql':
 876:                 $this->host && $dsn .= 'host=' . $this->host . ';';
 877:                 $this->port && $dsn .= 'port=' . $this->port . ';';
 878:                 $this->dbname && $dsn .= 'dbname=' . $this->dbname . ';';
 879:                 $this->unixSocket && $dsn .= 'unix_socket=' . $this->unixSocket . ';';
 880:                 $this->charset && $dsn .= 'charset=' . $this->charset;
 881:                 break;
 882: 
 883:             case 'sqlite':
 884:                 $dsn .= $this->path;
 885:                 break;
 886: 
 887:             case 'pgsql':
 888:                 $this->host && $dsn .= 'host=' . $this->host . ';';
 889:                 $this->port && $dsn .= 'port=' . $this->port . ';';
 890:                 $this->dbname && $dsn .= 'dbname=' . $this->dbname;
 891:                 break;
 892: 
 893:             default:
 894:                 throw new \RuntimeException(sprintf('Unsupported database driver: %s', $this->driver));
 895:         }
 896:         return $this->dsn = $dsn;
 897:     }
 898: 
 899:     /**
 900:      * Returns the original PDO object
 901:      *
 902:      * @return PDO
 903:      */
 904:     public function getPdo()
 905:     {
 906:         $this->connect();
 907:         return $this->pdo;
 908:     }
 909: 
 910:     /**
 911:      * Returns the prefix string of table name
 912:      *
 913:      * @return string
 914:      */
 915:     public function getTablePrefix()
 916:     {
 917:         return $this->tablePrefix;
 918:     }
 919: 
 920:     /**
 921:      * Returns the last executed SQL query
 922:      *
 923:      * @return string
 924:      */
 925:     public function getLastQuery()
 926:     {
 927:         return end($this->queries);
 928:     }
 929: 
 930:     /**
 931:      * Returns all executed SQL queries
 932:      *
 933:      * @return array
 934:      */
 935:     public function getQueries()
 936:     {
 937:         return $this->queries;
 938:     }
 939: 
 940:     /**
 941:      *  Returns the name of fields of specified table
 942:      *
 943:      * @param string $table
 944:      * @param bool $withPrefix
 945:      * @throws \PDOException
 946:      * @return array
 947:      */
 948:     public function getTableFields($table, $withPrefix = false)
 949:     {
 950:         $fullTable = $withPrefix ? $table : $this->getTable($table);
 951:         if (isset($this->tableFields[$fullTable])) {
 952:             return $this->tableFields[$fullTable];
 953:         } else {
 954:             $fields = array();
 955:             switch ($this->driver) {
 956:                 case 'mysql':
 957:                     $tableInfo = $this->fetchAll("SHOW COLUMNS FROM $fullTable");
 958:                     $fields = $this->filter($tableInfo, 'Field');
 959:                     break;
 960: 
 961:                 case 'sqlite':
 962:                     $tableInfo = $this->fetchAll("PRAGMA table_info($fullTable)");
 963:                     $fields = $this->filter($tableInfo, 'name');
 964:                     break;
 965: 
 966:                 case 'pgsql':
 967:                     $tableInfo = $this->fetchAll(
 968:                         "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS
 969:                         WHERE table_catalog = ? AND table_name = ?
 970:                         ORDER BY dtd_identifier ASC",
 971:                         array($this->dbname, $fullTable)
 972:                     );
 973:                     $fields = $this->filter($tableInfo, 'column_name');
 974:             }
 975:             if (empty($fields)) {
 976:                 // For SQLite and PostgreSQL
 977:                 throw new \PDOException(sprintf('Table or view "%s" not found', $fullTable));
 978:             }
 979:             return $this->tableFields[$table] = $fields;
 980:         }
 981:     }
 982: 
 983:     protected function filter($data, $name)
 984:     {
 985:         $fields = array();
 986:         foreach ($data as $row) {
 987:             $fields[] = $row[$name];
 988:         }
 989:         return $fields;
 990:     }
 991: 
 992:     protected function buildSqlObject(array &$data, $glue)
 993:     {
 994:         $query = array();
 995:         foreach ($data as $field => $value) {
 996:             if ($value instanceof \stdClass && isset($value->scalar)) {
 997:                 $query[] = $field . ' = ' . $value->scalar;
 998:                 unset($data[$field]);
 999:             } else {
1000:                 $query[] = $field . ' = ?';
1001:             }
1002:         }
1003:         return implode($glue, $query);
1004:     }
1005: 
1006:     /**
1007:      * Bind parameters to statement object
1008:      *
1009:      * @param \PDOStatement $stmt
1010:      * @param array $params
1011:      * @param array $types
1012:      */
1013:     protected function bindParameter(\PDOStatement $stmt, $params, $types)
1014:     {
1015:         !is_array($params) && $params = array($params);
1016:         !is_array($types) && $types = array($types);
1017: 
1018:         $isIndex = is_int(key($params));
1019:         $index = 1;
1020: 
1021:         foreach ($params as $name => $param) {
1022:             // Number index parameters
1023:             if ($isIndex) {
1024:                 if (isset($types[$index - 1])) {
1025:                     $stmt->bindValue($index, $param, $types[$index - 1]);
1026:                 } else {
1027:                     $stmt->bindValue($index, $param);
1028:                 }
1029:                 $index++;
1030:             // Named parameters
1031:             } else {
1032:                 if (isset($types[$name])) {
1033:                     $stmt->bindValue($name, $param, $types[$name]);
1034:                 } else {
1035:                     $stmt->bindValue($name, $param);
1036:                 }
1037:             }
1038:         }
1039:     }
1040: 
1041:     /**
1042:      * Execute a query with aggregate function
1043:      *
1044:      * @param string $fn
1045:      * @param string $table
1046:      * @param string $field
1047:      * @param mixed $conditions
1048:      * @return float
1049:      */
1050:     protected function executeAggregate($fn, $table, $field, $conditions)
1051:     {
1052:         $data = $this->selectAll($table, $conditions, $fn . '(' . $field . ')');
1053:         return $data ? (float)current($data[0]) : 0.0;
1054:     }
1055: }
1056: 
Wei Framework API documentation generated by ApiGen