Zend Framework入门教程之Zend_Db数据库操作详解
author:一佰互联 2019-04-26   click:126

本文实例讲述了Zend Framework中Zend_Db数据库操作方法。分享给大家供大家参考,具体如下:

引言:Zend操作数据库通过Zend_Db_Adapter

它可以连接多种数据库,可以是DB2数据库、MySQli数据库、Oracle数据库。等等。

只需要配置相应的参数就可以了。

下面通过案例来展示一下其连接数据库的过程。

连接mysql数据库

代码:

<?phprequire_once "Zend/Db.php";$params = array("host"=>"127.0.0.1",  "username"=>"root",  "password"=>"",  "dbname"=>"test"  );$db = Zend_Db::factory("PDO_Mysql",$params);

点评:

这是连接mysql的代码案例,提供相应的参数就可以了。连接不同的数据库,提供不同的参数。下面是sqlite的例子

代码:

<?phprequire_once "Zend/Db.php";$params = array("dbname"=>"test.mdb");$db = Zend_Db::factory("PDO_Sqlite",$params);

点评:

sqlite明显参数不一样了,只需要提供数据库名字就可以了。连接完数据库之后,就可以查询数据库信息以及操作数据库信息了。如果查询呢?

下面是查询的代码案例:

<?phprequire_once "Zend/Db.php";$params = array("host"=>"127.0.0.1",  "username"=>"root",  "password"=>"",  "dbname"=>"test"  );$db = Zend_Db::factory("PDO_Mysql",$params);$sql = $db->quoteInto("SELECT * FROM user WHERE id<?","5");$result = $db->query($sql);  //执行SQL查询$r_a = $result->fetchAll(); //返回结果数组print_r($r_a);

点评:

执行完上述代码,就会展示出数据库中前五条记录的信息。

那么这其中的玄机是什么呢?

我们来看一下源码。

我们来看看Db.php中的factory方法

public static function factory($adapter, $config = array()){    if ($config instanceof Zend_Config) {      $config = $config->toArray();    }    /*     * Convert Zend_Config argument to plain string     * adapter name and separate config object.     */    if ($adapter instanceof Zend_Config) {      if (isset($adapter->params)) {        $config = $adapter->params->toArray();      }      if (isset($adapter->adapter)) {        $adapter = (string) $adapter->adapter;      } else {        $adapter = null;      }    }    /*     * Verify that adapter parameters are in an array.     */    if (!is_array($config)) {      /**       * @see Zend_Db_Exception       */      require_once "Zend/Db/Exception.php";      throw new Zend_Db_Exception("Adapter parameters must be in an array or a Zend_Config object");    }    /*     * Verify that an adapter name has been specified.     */    if (!is_string($adapter) || empty($adapter)) {      /**       * @see Zend_Db_Exception       */      require_once "Zend/Db/Exception.php";      throw new Zend_Db_Exception("Adapter name must be specified in a string");    }    /*     * Form full adapter class name     */    $adapterNamespace = "Zend_Db_Adapter";    if (isset($config["adapterNamespace"])) {      if ($config["adapterNamespace"] != "") {        $adapterNamespace = $config["adapterNamespace"];      }      unset($config["adapterNamespace"]);    }    // Adapter no longer normalized- see http://framework.zend.com/issues/browse/ZF-5606    $adapterName = $adapterNamespace . "_";    $adapterName .= str_replace(" ", "_", ucwords(str_replace("_", " ", strtolower($adapter))));    print_r($adapterName);exit;    /*     * Load the adapter class. This throws an exception     * if the specified class cannot be loaded.     */    if (!class_exists($adapterName)) {      require_once "Zend/Loader.php";      Zend_Loader::loadClass($adapterName);    }    /*     * Create an instance of the adapter class.     * Pass the config to the adapter class constructor.     */    $dbAdapter = new $adapterName($config);    /*     * Verify that the object created is a descendent of the abstract adapter type.     */    if (! $dbAdapter instanceof Zend_Db_Adapter_Abstract) {      /**       * @see Zend_Db_Exception       */      require_once "Zend/Db/Exception.php";      throw new Zend_Db_Exception("Adapter class "$adapterName" does not extend Zend_Db_Adapter_Abstract");    }    return $dbAdapter;}

点评:这个方法就是核心了,代码量不多,但是作用很明确,它会通过你提供的两个参数,自动生成相应的数据库连接类的对象。具有一定的灵活性,机动性。

主要是其中的

$adapterName = $adapterNamespace . "_";$adapterName .= str_replace(" ", "_", ucwords(str_replace("_", " ", strtolower($adapter))));/* * Load the adapter class. This throws an exception * if the specified class cannot be loaded. */if (!class_exists($adapterName)) {      require_once "Zend/Loader.php";      Zend_Loader::loadClass($adapterName);}

这段代码会引入相应的数据库连接类,比如前面的两个例子,就是分别引入了Zend目录下Db目录下Adapter目录下Pdo目录下的mysql.php类。

不同的数据库,会引入不同的数据库文件。

我们来看看mysql.php类中的内容:

<?php/** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category  Zend * @package  Zend_Db * @subpackage Adapter * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) * @license  http://framework.zend.com/license/new-bsd   New BSD License * @version  $Id: Mysql.php 24593 2012-01-05 20:35:02Z matthew $ *//** * @see Zend_Db_Adapter_Pdo_Abstract */require_once "Zend/Db/Adapter/Pdo/Abstract.php";/** * Class for connecting to MySQL databases and performing common operations. * * @category  Zend * @package  Zend_Db * @subpackage Adapter * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) * @license  http://framework.zend.com/license/new-bsd   New BSD License */class Zend_Db_Adapter_Pdo_Mysql extends Zend_Db_Adapter_Pdo_Abstract{  /**   * PDO type.   *   * @var string   */  protected $_pdoType = "mysql";  /**   * Keys are UPPERCASE SQL datatypes or the constants   * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.   *   * Values are:   * 0 = 32-bit integer   * 1 = 64-bit integer   * 2 = float or decimal   *   * @var array Associative array of datatypes to values 0, 1, or 2.   */  protected $_numericDataTypes = array(    Zend_Db::INT_TYPE  => Zend_Db::INT_TYPE,    Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,    Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,    "INT"        => Zend_Db::INT_TYPE,    "INTEGER"      => Zend_Db::INT_TYPE,    "MEDIUMINT"     => Zend_Db::INT_TYPE,    "SMALLINT"      => Zend_Db::INT_TYPE,    "TINYINT"      => Zend_Db::INT_TYPE,    "BIGINT"       => Zend_Db::BIGINT_TYPE,    "SERIAL"       => Zend_Db::BIGINT_TYPE,    "DEC"        => Zend_Db::FLOAT_TYPE,    "DECIMAL"      => Zend_Db::FLOAT_TYPE,    "DOUBLE"       => Zend_Db::FLOAT_TYPE,    "DOUBLE PRECISION"  => Zend_Db::FLOAT_TYPE,    "FIXED"       => Zend_Db::FLOAT_TYPE,    "FLOAT"       => Zend_Db::FLOAT_TYPE  );  /**   * Override _dsn() and ensure that charset is incorporated in mysql   * @see Zend_Db_Adapter_Pdo_Abstract::_dsn()   */  protected function _dsn()  {    $dsn = parent::_dsn();    if (isset($this->_config["charset"])) {      $dsn .= ";charset=" . $this->_config["charset"];    }    return $dsn;  }  /**   * Creates a PDO object and connects to the database.   *   * @return void   * @throws Zend_Db_Adapter_Exception   */  protected function _connect()  {    if ($this->_connection) {      return;    }    if (!empty($this->_config["charset"])) {      $initCommand = "SET NAMES "" . $this->_config["charset"] . """;      $this->_config["driver_options"][1002] = $initCommand; // 1002 = PDO::MYSQL_ATTR_INIT_COMMAND    }    parent::_connect();  }  /**   * @return string   */  public function getQuoteIdentifierSymbol()  {    return "`";  }  /**   * Returns a list of the tables in the database.   *   * @return array   */  public function listTables()  {    return $this->fetchCol("SHOW TABLES");  }  /**   * Returns the column descriptions for a table.   *   * The return value is an associative array keyed by the column name,   * as returned by the RDBMS.   *   * The value of each array element is an associative array   * with the following keys:   *   * SCHEMA_NAME   => string; name of database or schema   * TABLE_NAME    => string;   * COLUMN_NAME   => string; column name   * COLUMN_POSITION => number; ordinal position of column in table   * DATA_TYPE    => string; SQL datatype name of column   * DEFAULT     => string; default expression of column, null if none   * NULLABLE     => boolean; true if column can have nulls   * LENGTH      => number; length of CHAR/VARCHAR   * SCALE      => number; scale of NUMERIC/DECIMAL   * PRECISION    => number; precision of NUMERIC/DECIMAL   * UNSIGNED     => boolean; unsigned property of an integer type   * PRIMARY     => boolean; true if column is part of the primary key   * PRIMARY_POSITION => integer; position of column in primary key   * IDENTITY     => integer; true if column is auto-generated with unique values   *   * @param string $tableName   * @param string $schemaName OPTIONAL   * @return array   */  public function describeTable($tableName, $schemaName = null)  {    // @todo use INFORMATION_SCHEMA someday when MySQL"s    // implementation has reasonably good performance and    // the version with this improvement is in wide use.    if ($schemaName) {      $sql = "DESCRIBE " . $this->quoteIdentifier("$schemaName.$tableName", true);    } else {      $sql = "DESCRIBE " . $this->quoteIdentifier($tableName, true);    }    $stmt = $this->query($sql);    // Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection    $result = $stmt->fetchAll(Zend_Db::FETCH_NUM);    $field  = 0;    $type  = 1;    $null  = 2;    $key   = 3;    $default = 4;    $extra  = 5;    $desc = array();    $i = 1;    $p = 1;    foreach ($result as $row) {      list($length, $scale, $precision, $unsigned, $primary, $primaryPosition, $identity)        = array(null, null, null, null, false, null, false);      if (preg_match("/unsigned/", $row[$type])) {        $unsigned = true;      }      if (preg_match("/^((?:var)?char)((d+))/", $row[$type], $matches)) {        $row[$type] = $matches[1];        $length = $matches[2];      } else if (preg_match("/^decimal((d+),(d+))/", $row[$type], $matches)) {        $row[$type] = "decimal";        $precision = $matches[1];        $scale = $matches[2];      } else if (preg_match("/^float((d+),(d+))/", $row[$type], $matches)) {        $row[$type] = "float";        $precision = $matches[1];        $scale = $matches[2];      } else if (preg_match("/^((?:big|medium|small|tiny)?int)((d+))/", $row[$type], $matches)) {        $row[$type] = $matches[1];        // The optional argument of a MySQL int type is not precision        // or length; it is only a hint for display width.      }      if (strtoupper($row[$key]) == "PRI") {        $primary = true;        $primaryPosition = $p;        if ($row[$extra] == "auto_increment") {          $identity = true;        } else {          $identity = false;        }        ++$p;      }      $desc[$this->foldCase($row[$field])] = array(        "SCHEMA_NAME"   => null, // @todo        "TABLE_NAME"    => $this->foldCase($tableName),        "COLUMN_NAME"   => $this->foldCase($row[$field]),        "COLUMN_POSITION" => $i,        "DATA_TYPE"    => $row[$type],        "DEFAULT"     => $row[$default],        "NULLABLE"     => (bool) ($row[$null] == "YES"),        "LENGTH"      => $length,        "SCALE"      => $scale,        "PRECISION"    => $precision,        "UNSIGNED"     => $unsigned,        "PRIMARY"     => $primary,        "PRIMARY_POSITION" => $primaryPosition,        "IDENTITY"     => $identity      );      ++$i;    }    return $desc;  }  /**   * Adds an adapter-specific LIMIT clause to the SELECT statement.   *   * @param string $sql   * @param integer $count   * @param integer $offset OPTIONAL   * @throws Zend_Db_Adapter_Exception   * @return string   */   public function limit($sql, $count, $offset = 0)   {    $count = intval($count);    if ($count <= 0) {      /** @see Zend_Db_Adapter_Exception */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid");    }    $offset = intval($offset);    if ($offset < 0) {      /** @see Zend_Db_Adapter_Exception */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");    }    $sql .= " LIMIT $count";    if ($offset > 0) {      $sql .= " OFFSET $offset";    }    return $sql;  }}

这里又引入了一个Abstract类,抽象类

<?php/** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category  Zend * @package  Zend_Db * @subpackage Adapter * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) * @license  http://framework.zend.com/license/new-bsd   New BSD License * @version  $Id: Abstract.php 24593 2012-01-05 20:35:02Z matthew $ *//** * @see Zend_Db_Adapter_Abstract */require_once "Zend/Db/Adapter/Abstract.php";/** * @see Zend_Db_Statement_Pdo */require_once "Zend/Db/Statement/Pdo.php";/** * Class for connecting to SQL databases and performing common operations using PDO. * * @category  Zend * @package  Zend_Db * @subpackage Adapter * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) * @license  http://framework.zend.com/license/new-bsd   New BSD License */abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract{  /**   * Default class name for a DB statement.   *   * @var string   */  protected $_defaultStmtClass = "Zend_Db_Statement_Pdo";  /**   * Creates a PDO DSN for the adapter from $this->_config settings.   *   * @return string   */  protected function _dsn()  {    // baseline of DSN parts    $dsn = $this->_config;    // don"t pass the username, password, charset, persistent and driver_options in the DSN    unset($dsn["username"]);    unset($dsn["password"]);    unset($dsn["options"]);    unset($dsn["charset"]);    unset($dsn["persistent"]);    unset($dsn["driver_options"]);    // use all remaining parts in the DSN    foreach ($dsn as $key => $val) {      $dsn[$key] = "$key=$val";    }    return $this->_pdoType . ":" . implode(";", $dsn);  }  /**   * Creates a PDO object and connects to the database.   *   * @return void   * @throws Zend_Db_Adapter_Exception   */  protected function _connect()  {    // if we already have a PDO object, no need to re-connect.    if ($this->_connection) {      return;    }    // get the dsn first, because some adapters alter the $_pdoType    $dsn = $this->_dsn();    // check for PDO extension    if (!extension_loaded("pdo")) {      /**       * @see Zend_Db_Adapter_Exception       */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception("The PDO extension is required for this adapter but the extension is not loaded");    }    // check the PDO driver is available    if (!in_array($this->_pdoType, PDO::getAvailableDrivers())) {      /**       * @see Zend_Db_Adapter_Exception       */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception("The " . $this->_pdoType . " driver is not currently installed");    }    // create PDO connection    $q = $this->_profiler->queryStart("connect", Zend_Db_Profiler::CONNECT);    // add the persistence flag if we find it in our config array    if (isset($this->_config["persistent"]) && ($this->_config["persistent"] == true)) {      $this->_config["driver_options"][PDO::ATTR_PERSISTENT] = true;    }    try {      $this->_connection = new PDO(        $dsn,        $this->_config["username"],        $this->_config["password"],        $this->_config["driver_options"]      );      $this->_profiler->queryEnd($q);      // set the PDO connection to perform case-folding on array keys, or not      $this->_connection->setAttribute(PDO::ATTR_CASE, $this->_caseFolding);      // always use exceptions.      $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);    } catch (PDOException $e) {      /**       * @see Zend_Db_Adapter_Exception       */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e);    }  }  /**   * Test if a connection is active   *   * @return boolean   */  public function isConnected()  {    return ((bool) ($this->_connection instanceof PDO));  }  /**   * Force the connection to close.   *   * @return void   */  public function closeConnection()  {    $this->_connection = null;  }  /**   * Prepares an SQL statement.   *   * @param string $sql The SQL statement with placeholders.   * @param array $bind An array of data to bind to the placeholders.   * @return PDOStatement   */  public function prepare($sql)  {    $this->_connect();    $stmtClass = $this->_defaultStmtClass;    if (!class_exists($stmtClass)) {      require_once "Zend/Loader.php";      Zend_Loader::loadClass($stmtClass);    }    $stmt = new $stmtClass($this, $sql);    $stmt->setFetchMode($this->_fetchMode);    return $stmt;  }  /**   * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.   *   * As a convention, on RDBMS brands that support sequences   * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence   * from the arguments and returns the last id generated by that sequence.   * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method   * returns the last value generated for such a column, and the table name   * argument is disregarded.   *   * On RDBMS brands that don"t support sequences, $tableName and $primaryKey   * are ignored.   *   * @param string $tableName  OPTIONAL Name of table.   * @param string $primaryKey OPTIONAL Name of primary key column.   * @return string   */  public function lastInsertId($tableName = null, $primaryKey = null)  {    $this->_connect();    return $this->_connection->lastInsertId();  }  /**   * Special handling for PDO query().   * All bind parameter names must begin with ":"   *   * @param string|Zend_Db_Select $sql The SQL statement with placeholders.   * @param array $bind An array of data to bind to the placeholders.   * @return Zend_Db_Statement_Pdo   * @throws Zend_Db_Adapter_Exception To re-throw PDOException.   */  public function query($sql, $bind = array())  {    if (empty($bind) && $sql instanceof Zend_Db_Select) {      $bind = $sql->getBind();    }    if (is_array($bind)) {      foreach ($bind as $name => $value) {        if (!is_int($name) && !preg_match("/^:/", $name)) {          $newName = ":$name";          unset($bind[$name]);          $bind[$newName] = $value;        }      }    }    try {      return parent::query($sql, $bind);    } catch (PDOException $e) {      /**       * @see Zend_Db_Statement_Exception       */      require_once "Zend/Db/Statement/Exception.php";      throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e);    }  }  /**   * Executes an SQL statement and return the number of affected rows   *   * @param mixed $sql The SQL statement with placeholders.   *           May be a string or Zend_Db_Select.   * @return integer   Number of rows that were modified   *           or deleted by the SQL statement   */  public function exec($sql)  {    if ($sql instanceof Zend_Db_Select) {      $sql = $sql->assemble();    }    try {      $affected = $this->getConnection()->exec($sql);      if ($affected === false) {        $errorInfo = $this->getConnection()->errorInfo();        /**         * @see Zend_Db_Adapter_Exception         */        require_once "Zend/Db/Adapter/Exception.php";        throw new Zend_Db_Adapter_Exception($errorInfo[2]);      }      return $affected;    } catch (PDOException $e) {      /**       * @see Zend_Db_Adapter_Exception       */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e);    }  }  /**   * Quote a raw string.   *   * @param string $value   Raw string   * @return string      Quoted string   */  protected function _quote($value)  {    if (is_int($value) || is_float($value)) {      return $value;    }    $this->_connect();    return $this->_connection->quote($value);  }  /**   * Begin a transaction.   */  protected function _beginTransaction()  {    $this->_connect();    $this->_connection->beginTransaction();  }  /**   * Commit a transaction.   */  protected function _commit()  {    $this->_connect();    $this->_connection->commit();  }  /**   * Roll-back a transaction.   */  protected function _rollBack() {    $this->_connect();    $this->_connection->rollBack();  }  /**   * Set the PDO fetch mode.   *   * @todo Support FETCH_CLASS and FETCH_INTO.   *   * @param int $mode A PDO fetch mode.   * @return void   * @throws Zend_Db_Adapter_Exception   */  public function setFetchMode($mode)  {    //check for PDO extension    if (!extension_loaded("pdo")) {      /**       * @see Zend_Db_Adapter_Exception       */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception("The PDO extension is required for this adapter but the extension is not loaded");    }    switch ($mode) {      case PDO::FETCH_LAZY:      case PDO::FETCH_ASSOC:      case PDO::FETCH_NUM:      case PDO::FETCH_BOTH:      case PDO::FETCH_NAMED:      case PDO::FETCH_OBJ:        $this->_fetchMode = $mode;        break;      default:        /**         * @see Zend_Db_Adapter_Exception         */        require_once "Zend/Db/Adapter/Exception.php";        throw new Zend_Db_Adapter_Exception("Invalid fetch mode "$mode" specified");        break;    }  }  /**   * Check if the adapter supports real SQL parameters.   *   * @param string $type "positional" or "named"   * @return bool   */  public function supportsParameters($type)  {    switch ($type) {      case "positional":      case "named":      default:        return true;    }  }  /**   * Retrieve server version in PHP style   *   * @return string   */  public function getServerVersion()  {    $this->_connect();    try {      $version = $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION);    } catch (PDOException $e) {      // In case of the driver doesn"t support getting attributes      return null;    }    $matches = null;    if (preg_match("/((?:[0-9]{1,2}.){1,3}[0-9]{1,2})/", $version, $matches)) {      return $matches[1];    } else {      return null;    }  }}

这个抽象类中又有另一个核心的抽象类。一些核心的方法都在这里

<?php/** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category  Zend * @package  Zend_Db * @subpackage Adapter * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) * @license  http://framework.zend.com/license/new-bsd   New BSD License * @version  $Id: Abstract.php 25229 2013-01-18 08:17:21Z frosch $ *//** * @see Zend_Db */require_once "Zend/Db.php";/** * @see Zend_Db_Select */require_once "Zend/Db/Select.php";/** * Class for connecting to SQL databases and performing common operations. * * @category  Zend * @package  Zend_Db * @subpackage Adapter * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) * @license  http://framework.zend.com/license/new-bsd   New BSD License */abstract class Zend_Db_Adapter_Abstract{  /**   * User-provided configuration   *   * @var array   */  protected $_config = array();  /**   * Fetch mode   *   * @var integer   */  protected $_fetchMode = Zend_Db::FETCH_ASSOC;  /**   * Query profiler object, of type Zend_Db_Profiler   * or a subclass of that.   *   * @var Zend_Db_Profiler   */  protected $_profiler;  /**   * Default class name for a DB statement.   *   * @var string   */  protected $_defaultStmtClass = "Zend_Db_Statement";  /**   * Default class name for the profiler object.   *   * @var string   */  protected $_defaultProfilerClass = "Zend_Db_Profiler";  /**   * Database connection   *   * @var object|resource|null   */  protected $_connection = null;  /**   * Specifies the case of column names retrieved in queries   * Options   * Zend_Db::CASE_NATURAL (default)   * Zend_Db::CASE_LOWER   * Zend_Db::CASE_UPPER   *   * @var integer   */  protected $_caseFolding = Zend_Db::CASE_NATURAL;  /**   * Specifies whether the adapter automatically quotes identifiers.   * If true, most SQL generated by Zend_Db classes applies   * identifier quoting automatically.   * If false, developer must quote identifiers themselves   * by calling quoteIdentifier().   *   * @var bool   */  protected $_autoQuoteIdentifiers = true;  /**   * Keys are UPPERCASE SQL datatypes or the constants   * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.   *   * Values are:   * 0 = 32-bit integer   * 1 = 64-bit integer   * 2 = float or decimal   *   * @var array Associative array of datatypes to values 0, 1, or 2.   */  protected $_numericDataTypes = array(    Zend_Db::INT_TYPE  => Zend_Db::INT_TYPE,    Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,    Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE  );  /** Weither or not that object can get serialized   *   * @var bool   */  protected $_allowSerialization = true;  /**   * Weither or not the database should be reconnected   * to that adapter when waking up   *   * @var bool   */  protected $_autoReconnectOnUnserialize = false;  /**   * Constructor.   *   * $config is an array of key/value pairs or an instance of Zend_Config   * containing configuration options. These options are common to most adapters:   *   * dbname     => (string) The name of the database to user   * username    => (string) Connect to the database as this username.   * password    => (string) Password associated with the username.   * host      => (string) What host to connect to, defaults to localhost   *   * Some options are used on a case-by-case basis by adapters:   *   * port      => (string) The port of the database   * persistent   => (boolean) Whether to use a persistent connection or not, defaults to false   * protocol    => (string) The network protocol, defaults to TCPIP   * caseFolding  => (int) style of case-alteration used for identifiers   * socket     => (string) The socket or named pipe that should be used   *   * @param array|Zend_Config $config An array or instance of Zend_Config having configuration data   * @throws Zend_Db_Adapter_Exception   */  public function __construct($config)  {    /*     * Verify that adapter parameters are in an array.     */    if (!is_array($config)) {      /*       * Convert Zend_Config argument to a plain array.       */      if ($config instanceof Zend_Config) {        $config = $config->toArray();      } else {        /**         * @see Zend_Db_Adapter_Exception         */        require_once "Zend/Db/Adapter/Exception.php";        throw new Zend_Db_Adapter_Exception("Adapter parameters must be in an array or a Zend_Config object");      }    }    $this->_checkRequiredOptions($config);    $options = array(      Zend_Db::CASE_FOLDING      => $this->_caseFolding,      Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers,      Zend_Db::FETCH_MODE       => $this->_fetchMode,    );    $driverOptions = array();    /*     * normalize the config and merge it with the defaults     */    if (array_key_exists("options", $config)) {      // can"t use array_merge() because keys might be integers      foreach ((array) $config["options"] as $key => $value) {        $options[$key] = $value;      }    }    if (array_key_exists("driver_options", $config)) {      if (!empty($config["driver_options"])) {        // can"t use array_merge() because keys might be integers        foreach ((array) $config["driver_options"] as $key => $value) {          $driverOptions[$key] = $value;        }      }    }    if (!isset($config["charset"])) {      $config["charset"] = null;    }    if (!isset($config["persistent"])) {      $config["persistent"] = false;    }    $this->_config = array_merge($this->_config, $config);    $this->_config["options"] = $options;    $this->_config["driver_options"] = $driverOptions;    // obtain the case setting, if there is one    if (array_key_exists(Zend_Db::CASE_FOLDING, $options)) {      $case = (int) $options[Zend_Db::CASE_FOLDING];      switch ($case) {        case Zend_Db::CASE_LOWER:        case Zend_Db::CASE_UPPER:        case Zend_Db::CASE_NATURAL:          $this->_caseFolding = $case;          break;        default:          /** @see Zend_Db_Adapter_Exception */          require_once "Zend/Db/Adapter/Exception.php";          throw new Zend_Db_Adapter_Exception("Case must be one of the following constants: "            . "Zend_Db::CASE_NATURAL, Zend_Db::CASE_LOWER, Zend_Db::CASE_UPPER");      }    }    if (array_key_exists(Zend_Db::FETCH_MODE, $options)) {      if (is_string($options[Zend_Db::FETCH_MODE])) {        $constant = "Zend_Db::FETCH_" . strtoupper($options[Zend_Db::FETCH_MODE]);        if(defined($constant)) {          $options[Zend_Db::FETCH_MODE] = constant($constant);        }      }      $this->setFetchMode((int) $options[Zend_Db::FETCH_MODE]);    }    // obtain quoting property if there is one    if (array_key_exists(Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) {      $this->_autoQuoteIdentifiers = (bool) $options[Zend_Db::AUTO_QUOTE_IDENTIFIERS];    }    // obtain allow serialization property if there is one    if (array_key_exists(Zend_Db::ALLOW_SERIALIZATION, $options)) {      $this->_allowSerialization = (bool) $options[Zend_Db::ALLOW_SERIALIZATION];    }    // obtain auto reconnect on unserialize property if there is one    if (array_key_exists(Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE, $options)) {      $this->_autoReconnectOnUnserialize = (bool) $options[Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE];    }    // create a profiler object    $profiler = false;    if (array_key_exists(Zend_Db::PROFILER, $this->_config)) {      $profiler = $this->_config[Zend_Db::PROFILER];      unset($this->_config[Zend_Db::PROFILER]);    }    $this->setProfiler($profiler);  }  /**   * Check for config options that are mandatory.   * Throw exceptions if any are missing.   *   * @param array $config   * @throws Zend_Db_Adapter_Exception   */  protected function _checkRequiredOptions(array $config)  {    // we need at least a dbname    if (! array_key_exists("dbname", $config)) {      /** @see Zend_Db_Adapter_Exception */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception("Configuration array must have a key for "dbname" that names the database instance");    }    if (! array_key_exists("password", $config)) {      /**       * @see Zend_Db_Adapter_Exception       */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception("Configuration array must have a key for "password" for login credentials");    }    if (! array_key_exists("username", $config)) {      /**       * @see Zend_Db_Adapter_Exception       */      require_once "Zend/Db/Adapter/Exception.php";      throw new Zend_Db_Adapter_Exception("Configuration array must have a key for "username" for login credentials");    }  }  /**   * Returns the underlying database connection object or resource.   * If not presently connected, this initiates the connection.   *   * @return object|resource|null   */  public function getConnection()  {    $this->_connect();    return $this->_connection;  }  /**   * Returns the configuration variables in this adapter.   *   * @return array   */  public function getConfig()  {    return $this->_config;  }  /**   * Set the adapter"s profiler object.   *   * The argument may be a boolean, an associative array, an instance of   * Zend_Db_Profiler, or an instance of Zend_Config.   *   * A boolean argument sets the profiler to enabled if true, or disabled if   * false. The profiler class is the adapter"s default profiler class,   * Zend_Db_Profiler.   *   * An instance of Zend_Db_Profiler sets the adapter"s instance to that   * object. The profiler is enabled and disabled separately.   *   * An associative array argument may contain any of the keys "enabled",   * "class", and "instance". The "enabled" and "instance" keys correspond to the   * boolean and object types documented above. The "class" key is used to name a   * class to use for a custom profiler. The class must be Zend_Db_Profiler or a   * subclass. The class is instantiated with no constructor arguments. The "class"   * option is ignored when the "instance" option is supplied.   *   * An object of type Zend_Config may contain the properties "enabled", "class", and   * "instance", just as if an associative array had been passed instead.   *   * @param Zend_Db_Profiler|Zend_Config|array|boolean $profiler   * @return Zend_Db_Adapter_Abstract Provides a fluent interface   * @throws Zend_Db_Profiler_Exception if the object instance or class specified   *     is not Zend_Db_Profiler or an extension of that class.   */  public function setProfiler($profiler)  {    $enabled     = null;    $profilerClass  = $this->_defaultProfilerClass;    $profilerInstance = null;    if ($profilerIsObject = is_object($profiler)) {      if ($profiler instanceof Zend_Db_Profiler) {        $profilerInstance = $profiler;      } else if ($profiler instanceof Zend_Config) {        $profiler = $profiler->toArray();      } else {        /**         * @see Zend_Db_Profiler_Exception         */        require_once "Zend/Db/Profiler/Exception.php";        throw new Zend_Db_Profiler_Exception("Profiler argument must be an instance of either Zend_Db_Profiler"          . " or Zend_Config when provided as an object");      }    }    if (is_array($profiler)) {      if (isset($profiler["enabled"])) {        $enabled = (bool) $profiler["enabled"];      }      if (isset($profiler["class"])) {        $profilerClass = $profiler["class"];      }      if (isset($profiler["instance"])) {        $profilerInstance = $profiler["instance"];      }    } else if (!$profilerIsObject) {      $enabled = (bool) $profiler;    }    if ($profilerInstance === null) {      if (!class_exists($profilerClass)) {        require_once "Zend/Loader.php";        Zend_Loader::loadClass($profilerClass);      }      $profilerInstance = new $profilerClass();    }    if (!$profilerInstance instanceof Zend_Db_Profiler) {      /** @see Zend_Db_Profiler_Exception */      require_once "Zend/Db/Profiler/Exception.php";      throw new Zend_Db_Profiler_Exception("Class " . get_class($profilerInstance) . " does not extend "        . "Zend_Db_Profiler");    }    if (null !== $enabled) {      $profilerInstance->setEnabled($enabled);    }    $this->_profiler = $profilerInstance;    return $this;  }  /**   * Returns the profiler for this adapter.   *   * @return Zend_Db_Profiler   */  public function getProfiler()  {    return $this->_profiler;  }  /**   * Get the default statement class.   *   * @return string   */  public function getStatementClass()  {    return $this->_defaultStmtClass;  }  /**   * Set the default statement class.   *   * @return Zend_Db_Adapter_Abstract Fluent interface   */  public function setStatementClass($class)  {    $this->_defaultStmtClass = $class;    return $this;  }  /**   * Prepares and executes an SQL statement with bound data.   *   * @param mixed $sql The SQL statement with placeholders.   *           May be a string or Zend_Db_Select.   * @param mixed $bind An array of data to bind to the placeholders.   * @return Zend_Db_Statement_Interface   */  public function query($sql, $bind = array())  {    // connect to the database if needed    $this->_connect();    // is the $sql a Zend_Db_Select object?    if ($sql instanceof Zend_Db_Select) {      if (empty($bind)) {        $bind = $sql->getBind();      }      $sql = $sql->assemble();    }    // make sure $bind to an array;    // don"t use (array) typecasting because    // because $bind may be a Zend_Db_Expr object    if (!is_array($bind)) {      $bind = array($bind);    }    // prepare and execute the statement with profiling    $stmt = $this->prepare($sql);    $stmt->execute($bind);    // return the results embedded in the prepared statement object    $stmt->setFetchMode($this->_fetchMode);    return $stmt;  }  /**   * Leave autocommit mode and begin a transaction.   *   * @return Zend_Db_Adapter_Abstract   */  public function beginTransaction()  {    $this->_connect();    $q = $this->_profiler->queryStart("begin", Zend_Db_Profiler::TRANSACTION);    $this->_beginTransaction();    $this->_profiler->queryEnd($q);    return $this;  }  /**   * Commit a transaction and return to autocommit mode.   *   * @return Zend_Db_Adapter_Abstract   */  public function commit()  {    $this->_connect();    $q = $this->_profiler->queryStart("commit", Zend_Db_Profiler::TRANSACTION);    $this->_commit();    $this->_profiler->queryEnd($q);    return $this;  }  /**   * Roll back a transaction and return to autocommit mode.   *   * @return Zend_Db_Adapter_Abstract   */  public function rollBack()  {    $this->_connect();    $q = $this->_profiler->queryStart("rollback", Zend_Db_Profiler::TRANSACTION);    $this->_rollBack();    $this->_profiler->queryEnd($q);    return $this;  }  /**   * Inserts a table row with specified data.   *   * @param mixed $table The table to insert data into.   * @param array $bind Column-value pairs.   * @return int The number of affected rows.   * @throws Zend_Db_Adapter_Exception   */  public function insert($table, array $bind)  {    // extract and quote col names from the array keys    $cols = array();    $vals = array();    $i = 0;    foreach ($bind as $col => $val) {      $cols[] = $this->quoteIdentifier($col, true);      if ($val instanceof Zend_Db_Expr) {        $vals[] = $val->__toString();        unset($bind[$col]);      } else {        if ($this->supportsParameters("positional")) {          $vals[] = "?";        } else {          if ($this->supportsParameters("named")) {            unset($bind[$col]);            $bind[":col".$i] = $val;            $vals[] = ":col".$i;            $i++;          } else {            /** @see Zend_Db_Adapter_Exception */            require_once "Zend/Db/Adapter/Exception.php";            throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn"t support positional or named binding");          }        }      }    }    // build the statement    $sql = "INSERT INTO "       . $this->quoteIdentifier($table, true)       . " (" . implode(", ", $cols) . ") "       . "VALUES (" . implode(", ", $vals) . ")";    // execute the statement and return the number of affected rows    if ($this->supportsParameters("positional")) {      $bind = array_values($bind);    }    $stmt = $this->query($sql, $bind);    $result = $stmt->rowCount();    return $result;  }  /**   * Updates table rows with specified data based on a WHERE clause.   *   * @param mixed    $table The table to update.   * @param array    $bind Column-value pairs.   * @param mixed    $where UPDATE WHERE clause(s).   * @return int     The number of affected rows.   * @throws Zend_Db_Adapter_Exception   */  public function update($table, array $bind, $where = "")  {    /**     * Build "col = ?" pairs for the statement,     * except for Zend_Db_Expr which is treated literally.     */    $set = array();    $i = 0;    foreach ($bind as $col => $val) {      if ($val instanceof Zend_Db_Expr) {        $val = $val->__toString();        unset($bind[$col]);      } else {        if ($this->supportsParameters("positional")) {          $val = "?";        } else {          if ($this->supportsParameters("named")) {            unset($bind[$col]);            $bind[":col".$i] = $val;            $val = ":col".$i;            $i++;          } else {            /** @see Zend_Db_Adapter_Exception */            require_once "Zend/Db/Adapter/Exception.php";            throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn"t support positional or named binding");          }        }      }      $set[] = $this->quoteIdentifier($col, true) . " = " . $val;    }    $where = $this->_whereExpr($where);    /**     * Build the UPDATE statement     */    $sql = "UPDATE "       . $this->quoteIdentifier($table, true)       . " SET " . implode(", ", $set)       . (($where) ? " WHERE $where" : "");    /**     * Execute the statement and return the number of affected rows     */    if ($this->supportsParameters("positional")) {      $stmt = $this->query($sql, array_values($bind));    } else {      $stmt = $this->query($sql, $bind);    }    $result = $stmt->rowCount();    return $result;  }  /**   * Deletes table rows based on a WHERE clause.   *   * @param mixed    $table The table to update.   * @param mixed    $where DELETE WHERE clause(s).   * @return int     The number of affected rows.   */  public function delete($table, $where = "")  {    $where = $this->_whereExpr($where);    /**     * Build the DELETE statement     */    $sql = "DELETE FROM "       . $this->quoteIdentifier($table, true)       . (($where) ? " WHERE $where" : "");    /**     * Execute the statement and return the number of affected rows     */    $stmt = $this->query($sql);    $result = $stmt->rowCount();    return $result;  }  /**   * Convert an array, string, or Zend_Db_Expr object   * into a string to put in a WHERE clause.   *   * @param mixed $where   * @return string   */  protected function _whereExpr($where)  {    if (empty($where)) {      return $where;    }    if (!is_array($where)) {      $where = array($where);    }    foreach ($where as $cond => &$term) {      // is $cond an int? (i.e. Not a condition)      if (is_int($cond)) {        // $term is the full condition        if ($term instanceof Zend_Db_Expr) {          $term = $term->__toString();        }      } else {        // $cond is the condition with placeholder,        // and $term is quoted into the condition        $term = $this->quoteInto($cond, $term);      }      $term = "(" . $term . ")";    }    $where = implode(" AND ", $where);    return $where;  }  /**   * Creates and returns a new Zend_Db_Select object for this adapter.   *   * @return Zend_Db_Select   */  public function select()  {    return new Zend_Db_Select($this);  }  /**   * Get the fetch mode.   *   * @return int   */  public function getFetchMode()  {    return $this->_fetchMode;  }  /**   * Fetches all SQL result rows as a sequential array.   * Uses the current fetchMode for the adapter.   *   * @param string|Zend_Db_Select $sql An SQL SELECT statement.   * @param mixed         $bind Data to bind into SELECT placeholders.   * @param mixed         $fetchMode Override current fetch mode.   * @return array   */  public function fetchAll($sql, $bind = array(), $fetchMode = null)  {    if ($fetchMode === null) {      $fetchMode = $this->_fetchMode;    }    $stmt = $this->query($sql, $bind);    $result = $stmt->fetchAll($fetchMode);    return $result;  }  /**   * Fetches the first row of the SQL result.   * Uses the current fetchMode for the adapter.   *   * @param string|Zend_Db_Select $sql An SQL SELECT statement.   * @param mixed $bind Data to bind into SELECT placeholders.   * @param mixed         $fetchMode Override current fetch mode.   * @return mixed Array, object, or scalar depending on fetch mode.   */  public function fetchRow($sql, $bind = array(), $fetchMode = null)  {    if ($fetchMode === null) {      $fetchMode = $this->_fetchMode;    }    $stmt = $this->query($sql, $bind);    $result = $stmt->fetch($fetchMode);    return $result;  }  /**   * Fetches all SQL result rows as an associative array.   *   * The first column is the key, the entire row array is the   * value. You should construct the query to be sure that   * the first column contains unique values, or else   * rows with duplicate values in the first column will   * overwrite previous data.   *   * @param string|Zend_Db_Select $sql An SQL SELECT statement.   * @param mixed $bind Data to bind into SELECT placeholders.   * @return array   */  public function fetchAssoc($sql, $bind = array())  {    $stmt = $this->query($sql, $bind);    $data = array();    while ($row = $stmt->fetch(Zend_Db::FETCH_ASSOC)) {      $tmp = array_values(array_slice($row, 0, 1));      $data[$tmp[0]] = $row;    }    return $data;  }  /**   * Fetches the first column of all SQL result rows as an array.   *   * @param string|Zend_Db_Select $sql An SQL SELECT statement.   * @param mixed $bind Data to bind into SELECT placeholders.   * @return array   */  public function fetchCol($sql, $bind = array())  {    $stmt = $this->query($sql, $bind);    $result = $stmt->fetchAll(Zend_Db::FETCH_COLUMN, 0);    return $result;  }  /**   * Fetches all SQL result rows as an array of key-value pairs.   *   * The first column is the key, the second column is the   * value.   *   * @param string|Zend_Db_Select $sql An SQL SELECT statement.   * @param mixed $bind Data to bind into SELECT placeholders.   * @return array   */  public function fetchPairs($sql, $bind = array())  {    $stmt = $this->query($sql, $bind);    $data = array();    while ($row = $stmt->fetch(Zend_Db::FETCH_NUM)) {      $data[$row[0]] = $row[1];    }    return $data;  }  /**   * Fetches the first column of the first row of the SQL result.   *   * @param string|Zend_Db_Select $sql An SQL SELECT statement.   * @param mixed $bind Data to bind into SELECT placeholders.   * @return string   */  public function fetchOne($sql, $bind = array())  {    $stmt = $this->query($sql, $bind);    $result = $stmt->fetchColumn(0);    return $result;  }  /**   * Quote a raw string.   *   * @param string $value   Raw string   * @return string      Quoted string   */  protected function _quote($value)  {    if (is_int($value)) {      return $value;    } elseif (is_float($value)) {      return sprintf("%F", $value);    }    return """ . addcslashes($value, "00\""32") . """;  }  /**   * Safely quotes a value for an SQL statement.   *   * If an array is passed as the value, the array values are quoted   * and then returned as a comma-separated string.   *   * @param mixed $value The value to quote.   * @param mixed $type OPTIONAL the SQL datatype name, or constant, or null.   * @return mixed An SQL-safe quoted value (or string of separated values).   */  public function quote($value, $type = null)  {    $this->_connect();    if ($value instanceof Zend_Db_Select) {      return "(" . $value->assemble() . ")";    }    if ($value instanceof Zend_Db_Expr) {      return $value->__toString();    }    if (is_array($value)) {      foreach ($value as &$val) {        $val = $this->quote($val, $type);      }      return implode(", ", $value);    }    if ($type !== null && array_key_exists($type = strtoupper($type), $this->_numericDataTypes)) {      $quotedValue = "0";      switch ($this->_numericDataTypes[$type]) {        case Zend_Db::INT_TYPE: // 32-bit integer          $quotedValue = (string) intval($value);          break;        case Zend_Db::BIGINT_TYPE: // 64-bit integer          // ANSI SQL-style hex literals (e.g. x"[dA-F]+")          // are not supported here, because these are string          // literals, not numeric literals.          if (preg_match("/^(             [+-]?         # optional sign             (?:              0[Xx][da-fA-F]+   # ODBC-style hexadecimal              |d+         # decimal or octal, or MySQL ZEROFILL decimal              (?:[eE][+-]?d+)?  # optional exponent on decimals or octals             )            )/x",            (string) $value, $matches)) {            $quotedValue = $matches[1];          }          break;        case Zend_Db::FLOAT_TYPE: // float or decimal          $quotedValue = sprintf("%F", $value);      }      return $quotedValue;    }    return $this->_quote($value);  }  /**   * Quotes a value and places into a piece of text at a placeholder.   *   * The placeholder is a question-mark; all placeholders will be replaced   * with the quoted value.  For example:   *   * <code>   * $text = "WHERE date < ?";   * $date = "2005-01-02";   * $safe = $sql->quoteInto($text, $date);   * // $safe = "WHERE date < "2005-01-02""   * </code>   *   * @param string $text The text with a placeholder.   * @param mixed  $value The value to quote.   * @param string $type OPTIONAL SQL datatype   * @param integer $count OPTIONAL count of placeholders to replace   * @return string An SQL-safe quoted value placed into the original text.   */  public function quoteInto($text, $value, $type = null, $count = null)  {    if ($count === null) {      return str_replace("?", $this->quote($value, $type), $text);    } else {      while ($count > 0) {        if (strpos($text, "?") !== false) {          $text = substr_replace($text, $this->quote($value, $type), strpos($text, "?"), 1);        }        --$count;      }      return $text;    }  }  /**   * Quotes an identifier.   *   * Accepts a string representing a qualified indentifier. For Example:   * <code>   * $adapter->quoteIdentifier("myschema.mytable")   * </code>   * Returns: "myschema"."mytable"   *   * Or, an array of one or more identifiers that may form a qualified identifier:   * <code>   * $adapter->quoteIdentifier(array("myschema","my.table"))   * </code>   * Returns: "myschema"."my.table"   *   * The actual quote character surrounding the identifiers may vary depending on   * the adapter.   *   * @param string|array|Zend_Db_Expr $ident The identifier.   * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.   * @return string The quoted identifier.   */  public function quoteIdentifier($ident, $auto=false)  {    return $this->_quoteIdentifierAs($ident, null, $auto);  }  /**   * Quote a column identifier and alias.   *   * @param string|array|Zend_Db_Expr