web/lib/Zend/Db/Adapter/Pdo/Abstract.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Db
       
    17  * @subpackage Adapter
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  * @version    $Id: Abstract.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    21  */
       
    22 
       
    23 
       
    24 /**
       
    25  * @see Zend_Db_Adapter_Abstract
       
    26  */
       
    27 require_once 'Zend/Db/Adapter/Abstract.php';
       
    28 
       
    29 
       
    30 /**
       
    31  * @see Zend_Db_Statement_Pdo
       
    32  */
       
    33 require_once 'Zend/Db/Statement/Pdo.php';
       
    34 
       
    35 
       
    36 /**
       
    37  * Class for connecting to SQL databases and performing common operations using PDO.
       
    38  *
       
    39  * @category   Zend
       
    40  * @package    Zend_Db
       
    41  * @subpackage Adapter
       
    42  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    43  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    44  */
       
    45 abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract
       
    46 {
       
    47 
       
    48     /**
       
    49      * Default class name for a DB statement.
       
    50      *
       
    51      * @var string
       
    52      */
       
    53     protected $_defaultStmtClass = 'Zend_Db_Statement_Pdo';
       
    54 
       
    55     /**
       
    56      * Creates a PDO DSN for the adapter from $this->_config settings.
       
    57      *
       
    58      * @return string
       
    59      */
       
    60     protected function _dsn()
       
    61     {
       
    62         // baseline of DSN parts
       
    63         $dsn = $this->_config;
       
    64 
       
    65         // don't pass the username, password, charset, persistent and driver_options in the DSN
       
    66         unset($dsn['username']);
       
    67         unset($dsn['password']);
       
    68         unset($dsn['options']);
       
    69         unset($dsn['charset']);
       
    70         unset($dsn['persistent']);
       
    71         unset($dsn['driver_options']);
       
    72 
       
    73         // use all remaining parts in the DSN
       
    74         foreach ($dsn as $key => $val) {
       
    75             $dsn[$key] = "$key=$val";
       
    76         }
       
    77 
       
    78         return $this->_pdoType . ':' . implode(';', $dsn);
       
    79     }
       
    80 
       
    81     /**
       
    82      * Creates a PDO object and connects to the database.
       
    83      *
       
    84      * @return void
       
    85      * @throws Zend_Db_Adapter_Exception
       
    86      */
       
    87     protected function _connect()
       
    88     {
       
    89         // if we already have a PDO object, no need to re-connect.
       
    90         if ($this->_connection) {
       
    91             return;
       
    92         }
       
    93 
       
    94         // get the dsn first, because some adapters alter the $_pdoType
       
    95         $dsn = $this->_dsn();
       
    96 
       
    97         // check for PDO extension
       
    98         if (!extension_loaded('pdo')) {
       
    99             /**
       
   100              * @see Zend_Db_Adapter_Exception
       
   101              */
       
   102             require_once 'Zend/Db/Adapter/Exception.php';
       
   103             throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded');
       
   104         }
       
   105 
       
   106         // check the PDO driver is available
       
   107         if (!in_array($this->_pdoType, PDO::getAvailableDrivers())) {
       
   108             /**
       
   109              * @see Zend_Db_Adapter_Exception
       
   110              */
       
   111             require_once 'Zend/Db/Adapter/Exception.php';
       
   112             throw new Zend_Db_Adapter_Exception('The ' . $this->_pdoType . ' driver is not currently installed');
       
   113         }
       
   114 
       
   115         // create PDO connection
       
   116         $q = $this->_profiler->queryStart('connect', Zend_Db_Profiler::CONNECT);
       
   117 
       
   118         // add the persistence flag if we find it in our config array
       
   119         if (isset($this->_config['persistent']) && ($this->_config['persistent'] == true)) {
       
   120             $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true;
       
   121         }
       
   122 
       
   123         try {
       
   124             $this->_connection = new PDO(
       
   125                 $dsn,
       
   126                 $this->_config['username'],
       
   127                 $this->_config['password'],
       
   128                 $this->_config['driver_options']
       
   129             );
       
   130 
       
   131             $this->_profiler->queryEnd($q);
       
   132 
       
   133             // set the PDO connection to perform case-folding on array keys, or not
       
   134             $this->_connection->setAttribute(PDO::ATTR_CASE, $this->_caseFolding);
       
   135 
       
   136             // always use exceptions.
       
   137             $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
       
   138 
       
   139         } catch (PDOException $e) {
       
   140             /**
       
   141              * @see Zend_Db_Adapter_Exception
       
   142              */
       
   143             require_once 'Zend/Db/Adapter/Exception.php';
       
   144             throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e);
       
   145         }
       
   146 
       
   147     }
       
   148 
       
   149     /**
       
   150      * Test if a connection is active
       
   151      *
       
   152      * @return boolean
       
   153      */
       
   154     public function isConnected()
       
   155     {
       
   156         return ((bool) ($this->_connection instanceof PDO));
       
   157     }
       
   158 
       
   159     /**
       
   160      * Force the connection to close.
       
   161      *
       
   162      * @return void
       
   163      */
       
   164     public function closeConnection()
       
   165     {
       
   166         $this->_connection = null;
       
   167     }
       
   168 
       
   169     /**
       
   170      * Prepares an SQL statement.
       
   171      *
       
   172      * @param string $sql The SQL statement with placeholders.
       
   173      * @param array $bind An array of data to bind to the placeholders.
       
   174      * @return PDOStatement
       
   175      */
       
   176     public function prepare($sql)
       
   177     {
       
   178         $this->_connect();
       
   179         $stmtClass = $this->_defaultStmtClass;
       
   180         if (!class_exists($stmtClass)) {
       
   181             require_once 'Zend/Loader.php';
       
   182             Zend_Loader::loadClass($stmtClass);
       
   183         }
       
   184         $stmt = new $stmtClass($this, $sql);
       
   185         $stmt->setFetchMode($this->_fetchMode);
       
   186         return $stmt;
       
   187     }
       
   188 
       
   189     /**
       
   190      * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
       
   191      *
       
   192      * As a convention, on RDBMS brands that support sequences
       
   193      * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
       
   194      * from the arguments and returns the last id generated by that sequence.
       
   195      * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
       
   196      * returns the last value generated for such a column, and the table name
       
   197      * argument is disregarded.
       
   198      *
       
   199      * On RDBMS brands that don't support sequences, $tableName and $primaryKey
       
   200      * are ignored.
       
   201      *
       
   202      * @param string $tableName   OPTIONAL Name of table.
       
   203      * @param string $primaryKey  OPTIONAL Name of primary key column.
       
   204      * @return string
       
   205      */
       
   206     public function lastInsertId($tableName = null, $primaryKey = null)
       
   207     {
       
   208         $this->_connect();
       
   209         return $this->_connection->lastInsertId();
       
   210     }
       
   211 
       
   212     /**
       
   213      * Special handling for PDO query().
       
   214      * All bind parameter names must begin with ':'
       
   215      *
       
   216      * @param string|Zend_Db_Select $sql The SQL statement with placeholders.
       
   217      * @param array $bind An array of data to bind to the placeholders.
       
   218      * @return Zend_Db_Statement_Pdo
       
   219      * @throws Zend_Db_Adapter_Exception To re-throw PDOException.
       
   220      */
       
   221     public function query($sql, $bind = array())
       
   222     {
       
   223         if (empty($bind) && $sql instanceof Zend_Db_Select) {
       
   224             $bind = $sql->getBind();
       
   225         }
       
   226 
       
   227         if (is_array($bind)) {
       
   228             foreach ($bind as $name => $value) {
       
   229                 if (!is_int($name) && !preg_match('/^:/', $name)) {
       
   230                     $newName = ":$name";
       
   231                     unset($bind[$name]);
       
   232                     $bind[$newName] = $value;
       
   233                 }
       
   234             }
       
   235         }
       
   236 
       
   237         try {
       
   238             return parent::query($sql, $bind);
       
   239         } catch (PDOException $e) {
       
   240             /**
       
   241              * @see Zend_Db_Statement_Exception
       
   242              */
       
   243             require_once 'Zend/Db/Statement/Exception.php';
       
   244             throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e);
       
   245         }
       
   246     }
       
   247 
       
   248     /**
       
   249      * Executes an SQL statement and return the number of affected rows
       
   250      *
       
   251      * @param  mixed  $sql  The SQL statement with placeholders.
       
   252      *                      May be a string or Zend_Db_Select.
       
   253      * @return integer      Number of rows that were modified
       
   254      *                      or deleted by the SQL statement
       
   255      */
       
   256     public function exec($sql)
       
   257     {
       
   258         if ($sql instanceof Zend_Db_Select) {
       
   259             $sql = $sql->assemble();
       
   260         }
       
   261 
       
   262         try {
       
   263             $affected = $this->getConnection()->exec($sql);
       
   264 
       
   265             if ($affected === false) {
       
   266                 $errorInfo = $this->getConnection()->errorInfo();
       
   267                 /**
       
   268                  * @see Zend_Db_Adapter_Exception
       
   269                  */
       
   270                 require_once 'Zend/Db/Adapter/Exception.php';
       
   271                 throw new Zend_Db_Adapter_Exception($errorInfo[2]);
       
   272             }
       
   273 
       
   274             return $affected;
       
   275         } catch (PDOException $e) {
       
   276             /**
       
   277              * @see Zend_Db_Adapter_Exception
       
   278              */
       
   279             require_once 'Zend/Db/Adapter/Exception.php';
       
   280             throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e);
       
   281         }
       
   282     }
       
   283 
       
   284     /**
       
   285      * Quote a raw string.
       
   286      *
       
   287      * @param string $value     Raw string
       
   288      * @return string           Quoted string
       
   289      */
       
   290     protected function _quote($value)
       
   291     {
       
   292         if (is_int($value) || is_float($value)) {
       
   293             return $value;
       
   294         }
       
   295         $this->_connect();
       
   296         return $this->_connection->quote($value);
       
   297     }
       
   298 
       
   299     /**
       
   300      * Begin a transaction.
       
   301      */
       
   302     protected function _beginTransaction()
       
   303     {
       
   304         $this->_connect();
       
   305         $this->_connection->beginTransaction();
       
   306     }
       
   307 
       
   308     /**
       
   309      * Commit a transaction.
       
   310      */
       
   311     protected function _commit()
       
   312     {
       
   313         $this->_connect();
       
   314         $this->_connection->commit();
       
   315     }
       
   316 
       
   317     /**
       
   318      * Roll-back a transaction.
       
   319      */
       
   320     protected function _rollBack() {
       
   321         $this->_connect();
       
   322         $this->_connection->rollBack();
       
   323     }
       
   324 
       
   325     /**
       
   326      * Set the PDO fetch mode.
       
   327      *
       
   328      * @todo Support FETCH_CLASS and FETCH_INTO.
       
   329      *
       
   330      * @param int $mode A PDO fetch mode.
       
   331      * @return void
       
   332      * @throws Zend_Db_Adapter_Exception
       
   333      */
       
   334     public function setFetchMode($mode)
       
   335     {
       
   336         //check for PDO extension
       
   337         if (!extension_loaded('pdo')) {
       
   338             /**
       
   339              * @see Zend_Db_Adapter_Exception
       
   340              */
       
   341             require_once 'Zend/Db/Adapter/Exception.php';
       
   342             throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded');
       
   343         }
       
   344         switch ($mode) {
       
   345             case PDO::FETCH_LAZY:
       
   346             case PDO::FETCH_ASSOC:
       
   347             case PDO::FETCH_NUM:
       
   348             case PDO::FETCH_BOTH:
       
   349             case PDO::FETCH_NAMED:
       
   350             case PDO::FETCH_OBJ:
       
   351                 $this->_fetchMode = $mode;
       
   352                 break;
       
   353             default:
       
   354                 /**
       
   355                  * @see Zend_Db_Adapter_Exception
       
   356                  */
       
   357                 require_once 'Zend/Db/Adapter/Exception.php';
       
   358                 throw new Zend_Db_Adapter_Exception("Invalid fetch mode '$mode' specified");
       
   359                 break;
       
   360         }
       
   361     }
       
   362 
       
   363     /**
       
   364      * Check if the adapter supports real SQL parameters.
       
   365      *
       
   366      * @param string $type 'positional' or 'named'
       
   367      * @return bool
       
   368      */
       
   369     public function supportsParameters($type)
       
   370     {
       
   371         switch ($type) {
       
   372             case 'positional':
       
   373             case 'named':
       
   374             default:
       
   375                 return true;
       
   376         }
       
   377     }
       
   378 
       
   379     /**
       
   380      * Retrieve server version in PHP style
       
   381      *
       
   382      * @return string
       
   383      */
       
   384     public function getServerVersion()
       
   385     {
       
   386         $this->_connect();
       
   387         try {
       
   388             $version = $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION);
       
   389         } catch (PDOException $e) {
       
   390             // In case of the driver doesn't support getting attributes
       
   391             return null;
       
   392         }
       
   393         $matches = null;
       
   394         if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $version, $matches)) {
       
   395             return $matches[1];
       
   396         } else {
       
   397             return null;
       
   398         }
       
   399     }
       
   400 }
       
   401