Source for file PdoConnector.php

Documentation is available at PdoConnector.php

  1. <?php
  2.  
  3. ///////////////////////////////////////////////////////////////////////////////
  4. /**
  5.  * IConnector implementation for PHP Data Objects.
  6.  *
  7.  * System requirements:
  8.  * <ul>
  9.  * <li>PHP 5</li>
  10.  * <li>The {@link PHP_MANUAL#book.pdo PHP Data Objects}</li>
  11.  * </ul>
  12.  *
  13.  * This library is free software: you can redistribute it and/or modify
  14.  * it under the terms of the GNU Lesser General Public License as published by
  15.  * the Free Software Foundation, either version 3 of the License, or
  16.  * (at your option) any later version.
  17.  * The Connector library is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20.  * {@link http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License}
  21.  * for more details.
  22.  *
  23.  * @author Per Egil Roksvaag
  24.  * @copyright 2009 Per Egil Roksvaag
  25.  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  26.  * @package connector
  27.  * @version 2.0.0
  28.  */
  29.  
  30. ///////////////////////////////////////////////////////////////////////////////
  31. /**
  32.  * Includes the parent class.
  33.  */
  34.  
  35. require_once("BaseConnector.php");
  36.  
  37. ///////////////////////////////////////////////////////////////////////////////
  38. /**
  39.  * IConnector implementation for the PHP Data Objects.
  40.  * @package connector
  41.  */
  42.  
  43. class PdoConnector extends BaseConnector implements IConnector
  44. {
  45.     ///////////////////////////////////////////////////////////////////////////
  46.     /**
  47.      * Open a PDO connection and set global options.
  48.      *
  49.      * @param array $connection An associated array of connection settings, like host and user name.
  50.      * @param array $options An associated array of global options for the resulting instance.
  51.      * @return PdoConnector 
  52.      */
  53.  
  54.     public function PdoConnector($connection$options array())
  55.     {
  56.         try
  57.         {
  58.             if($this->open($connection))
  59.             {
  60.                 switch($this->conn->getAttribute(PDO::ATTR_DRIVER_NAME))
  61.                 {
  62.                     case "odbc"break;
  63.                     case "mssql"break;
  64.                     case "mysql"break;
  65.                 }
  66.                 parent::BaseConnector($options);
  67.             }
  68.             else if($this->lookup("throwException"$options))
  69.             {
  70.                 throw new Exception("PdoConnector error: Connection failed.");
  71.             }
  72.             else if($this->lookup(self::LOG_ERROR$options))
  73.             {
  74.                 $log "PdoConnector error: Connection failed in ";
  75.                 error_log($log.$_SERVER["SCRIPT_FILENAME"]);
  76.             }
  77.         }
  78.         catch (PDOException $e)
  79.         {
  80.             $log "PdoConnector error: ".$e->getMessage();
  81.             error_log($log.$_SERVER["SCRIPT_FILENAME"]);
  82.         }
  83.     }
  84.  
  85.     ///////////////////////////////////////////////////////////////////////////
  86.     /**
  87.      * Open a database connection.
  88.      * @param array $connection An associated array of connection settings, like host and user name.
  89.      * @return bool <var>true</var>, if a database connection was successfully opened, <var>false</var> otherwise.
  90.      */
  91.  
  92.     protected function open($connection)
  93.     {
  94.         $hostname $this->lookup(self::CONN_HOSTNAME$connection);
  95.         $database $this->lookup(self::CONN_DATABASE$connection);
  96.         $username $this->lookup(self::CONN_USERNAME$connection);
  97.         $password $this->lookup(self::CONN_PASSWORD$connection);
  98.  
  99.         $persistent $this->lookup(self::CONN_PERSISTENT$connectionfalse);
  100.         $native $this->lookup(self::CONN_NATIVE$connectionarray());
  101.         $driver $this->lookup(self::CONN_DRIVER$connection);
  102.         $port $this->lookup(self::CONN_PORT$connection);
  103.  
  104.         if($driver == "odbc" && $database)
  105.         {
  106.             $dsn "{$driver}:{$database}";
  107.         }
  108.         else
  109.         {
  110.             $dsn "{$driver}:";
  111.             $database && $dsn.= "dbname={$database};";
  112.             $hostname && $dsn.= "host={$hostname};";
  113.             $port && $dsn.= "port={$port};";
  114.         }
  115.  
  116.         $native array();
  117.         $native[PDO::ATTR_PERSISTENT$persistent;
  118.  
  119.         switch($driver)
  120.         {
  121.             case "odbc":
  122.             case "mssql"$this->conn = new PDO($dsn$username$password)break;
  123.             default$this->conn = new PDO($dsn$username$password$native)break;
  124.         }
  125.         return is_object($this->conn);
  126.     }
  127.  
  128.     ///////////////////////////////////////////////////////////////////////////
  129.     /**
  130.      * Send a SQL SELECT query to the database and get the query result.
  131.      *
  132.      * @see IConnector::select().
  133.      * @param string $query A SQL query to execute on a database.
  134.      * @param array $param An associated array of values to be used in the $query.
  135.      * @param array $map An array of type definitions for the <var>$param</var> values.
  136.      * @param array $options An associated array of options, see the {@tutorial connector.pkg#options.element}.
  137.      * @throws Exception when $param doesn't match the type definition $map.
  138.      * @return array The query result as a table (array of associated arrays).
  139.      */
  140.  
  141.     public function select($query$param array()$map array()$options array())
  142.     {
  143.         $param TypeValidator::check($param$map);
  144.         $query $this->bind($query$param$stack$options);
  145.         $query $this->build($query$options);
  146.         $hash $this->getHash($query$stack$options);
  147.  
  148.         if($this->lookup(self::LOG_DEBUG$options))
  149.         {
  150.             $log1 "PdoConnector debug: Select query in ";
  151.             $log2 $stack LB."Params: ".@implode(", "$stack"";
  152.             error_log($log1.$_SERVER["SCRIPT_FILENAME"].LB.$query.$log2);
  153.         }
  154.         if($this->getCache($hash$table$options))
  155.         {
  156.             return $table;
  157.         }
  158.         if($this->lookup(self::PARAM_QUERIES$options))
  159.         {
  160.             $stmt $this->conn->prepare($query);
  161.             $this->bindStatement($stmt$stack$options);
  162.             $success $stmt->execute();
  163.         }
  164.         else
  165.         {
  166.             $stmt $this->conn->query($query);
  167.             $success is_object($stmt);
  168.         }
  169.         if($success)
  170.         {
  171.             do $table[$this->fetch($stmt$options);
  172.             while($stmt->nextRowset());
  173.             $stmt->closeCursor();
  174.  
  175.             if(count($table== 1$table current($table);
  176.             $this->setCache($hash$table$options);
  177.             return $table;
  178.         }
  179.         if($this->lookup(self::LOG_ERROR$options))
  180.         {
  181.             $log1 "PdoConnector error: Select query in ";
  182.             $log2 $stack LB."Params: ".@implode(", "$stack"";
  183.             error_log($log1.$_SERVER["SCRIPT_FILENAME"].LB.$query.$log2);
  184.             error_log("PdoConnector error: ".end($stmt->errorInfo()));
  185.         }
  186.         return false;
  187.     }
  188.  
  189.     ///////////////////////////////////////////////////////////////////////////
  190.     /**
  191.      * Send a SQL INSERT query to the database and get the IDENTITY ID
  192.      * generated from the last INSERT operation (if any).
  193.      *
  194.      * @see IConnector::insert().
  195.      * @param string $query A SQL query to execute on a database.
  196.      * @param array $param An associated array of values to be used in the $query.
  197.      * @param array $map An array of type definitions for the <var>$param</var> values.
  198.      * @param array $options An associated array of options, see the {@tutorial connector.pkg#options.element}.
  199.      * @throws Exception when $param doesn't match the type definition $map.
  200.      * @return int The IDENTITY ID of the last inserted row.
  201.      */
  202.  
  203.     public function insert($query$param array()$map array()$options array())
  204.     {
  205.         $param TypeValidator::check($param$map);
  206.         $query $this->bind($query$param$stack$options);
  207.         $driver $this->conn->getAttribute(PDO::ATTR_DRIVER_NAME);
  208.  
  209.         switch($driver)
  210.         {
  211.             case "odbc":
  212.             case "mssql"$query rtrim($query";").";".LB."SELECT SCOPE_IDENTITY();"break;
  213.         }
  214.         if($this->lookup(self::LOG_DEBUG$options))
  215.         {
  216.             $log1 "PdoConnector debug: Insert query in ";
  217.             $log2 $stack LB."Params: ".@implode(", "$stack"";
  218.             error_log($log1.$_SERVER["SCRIPT_FILENAME"].LB.$query.$log2);
  219.         }
  220.         if($this->lookup(self::PARAM_QUERIES$options))
  221.         {
  222.             $stmt $this->conn->prepare($query);
  223.             $this->bindStatement($stmt$stack$options);
  224.             $success $stmt->execute();
  225.         }
  226.         else
  227.         {
  228.             $stmt $this->conn->query($query);
  229.             $success = (bool)$stmt;
  230.         }
  231.         if($success)
  232.         {
  233.             if(in_array($driverarray("mssql""odbc")))
  234.             {
  235.                 do $row $stmt->fetch(PDO::FETCH_NUM);
  236.                 while($stmt->nextRowset());
  237.                 $stmt->closeCursor();
  238.  
  239.                 $key is_array($rowcurrent($rownull;
  240.                 return is_numeric($key? (int)$key $key;
  241.             }
  242.             else
  243.             {
  244.                 $key $this->conn->lastInsertId();
  245.                 $stmt->closeCursor();
  246.                 return ($key !== 0$key null;
  247.             }
  248.          }
  249.         if($this->lookup(self::LOG_ERROR$options))
  250.         {
  251.             $log1 "PdoConnector error: Insert query in ";
  252.             $log2 $stack LB."Params: ".@implode(", "$stack"";
  253.             error_log($log1.$_SERVER["SCRIPT_FILENAME"].LB.$query.$log2);
  254.             error_log("PdoConnector error: ".end($stmt->errorInfo()));
  255.         }
  256.         return false;
  257.     }
  258.  
  259.     ///////////////////////////////////////////////////////////////////////////
  260.     /**
  261.      * Send a SQL UPDATE query to the database and get the number of rows
  262.      * updates by the query.
  263.      *
  264.      * @see IConnector::update().
  265.      * @param string $query A SQL query to execute on a database.
  266.      * @param array $param An associated array of values to be used in the $query.
  267.      * @param array $map An array of type definitions for the <var>$param</var> values.
  268.      * @param array $options An associated array of options, see the {@tutorial connector.pkg#options.element}.
  269.      * @throws Exception when $param doesn't match the type definition $map.
  270.      * @return int The number of rows updates by the query.
  271.      */
  272.  
  273.     public function update($query$param array()$map array()$options array())
  274.     {
  275.         $param TypeValidator::check($param$map);
  276.         $query $this->bind($query$param$stack$options);
  277.  
  278.         if($this->lookup(self::LOG_DEBUG$options))
  279.         {
  280.             $log1 "PdoConnector debug: Update query in ";
  281.             $log2 $stack LB."Params: ".@implode(", "$stack"";
  282.             error_log($log1.$_SERVER["SCRIPT_FILENAME"].LB.$query.$log2);
  283.         }
  284.         if($this->lookup(self::PARAM_QUERIES$options))
  285.         {
  286.             $stmt $this->conn->prepare($query);
  287.             $this->bindStatement($stmt$stack$options);
  288.             $success $stmt->execute();
  289.         }
  290.         else
  291.         {
  292.             $stmt $this->conn->query($query);
  293.             $success = (bool)$stmt;
  294.         }
  295.         if($success)
  296.         {
  297.             return $stmt->rowCount();
  298.          }
  299.         if($this->lookup(self::LOG_ERROR$options))
  300.         {
  301.             $log1 "PdoConnector error: Update query in ";
  302.             $log2 $stack LB."Params: ".@implode(", "$stack"";
  303.             error_log($log1.$_SERVER["SCRIPT_FILENAME"].LB.$query.$log2);
  304.             error_log("PdoConnector error: ".end($stmt->errorInfo()));
  305.         }
  306.         return false;
  307.     }
  308.  
  309.     ///////////////////////////////////////////////////////////////////////////
  310.     /**
  311.      * Send a SQL DELETE query to the database and get the number of rows
  312.      * deleted by the query.
  313.      *
  314.      * @see IConnector::delete().
  315.      * @param string $query A SQL query to execute on a database.
  316.      * @param array $param An associated array of values to be used in the $query.
  317.      * @param array $map An array of type definitions for the <var>$param</var> values.
  318.      * @param array $options An associated array of options, see the {@tutorial connector.pkg#options.element}.
  319.      * @throws Exception when $param doesn't match the type definition $map.
  320.      * @return int The number of rows deleted by the query.
  321.      */
  322.  
  323.     public function delete($query$param array()$map array()$options array())
  324.     {
  325.         $param TypeValidator::check($param$map);
  326.         $query $this->bind($query$param$stack$options);
  327.  
  328.         if($this->lookup(self::LOG_DEBUG$options))
  329.         {
  330.             $log1 "PdoConnector debug: Delete query in ";
  331.             $log2 $stack LB."Params: ".@implode(", "$stack"";
  332.             error_log($log1.$_SERVER["SCRIPT_FILENAME"].LB.$query.$log2);
  333.         }
  334.         if($this->lookup(self::PARAM_QUERIES$options))
  335.         {
  336.             $stmt $this->conn->prepare($query);
  337.             $this->bindStatement($stmt$stack$options);
  338.             $success $stmt->execute();
  339.         }
  340.         else
  341.         {
  342.             $stmt $this->conn->query($query);
  343.             $success = (bool)$stmt;
  344.         }
  345.         if($success)
  346.         {
  347.             return $stmt->rowCount();
  348.          }
  349.         if($this->lookup(self::LOG_ERROR$options))
  350.         {
  351.             $log1 "PdoConnector error: Delete query in ";
  352.             $log2 $stack LB."Params: ".@implode(", "$stack"";
  353.             error_log($log1.$_SERVER["SCRIPT_FILENAME"].LB.$query.$log2);
  354.             error_log("PdoConnector error: ".end($stmt->errorInfo()));
  355.         }
  356.         return false;
  357.     }
  358.  
  359.     ///////////////////////////////////////////////////////////////////////////
  360.     /**
  361.      * Begins a transaction on the current connection.
  362.      * The current transaction includes all statements on the connection that
  363.      * were executed after the call to transaction() and before any calls
  364.      * to rollback() or commit().
  365.      *
  366.      * @see IConnector::transaction().
  367.      * @param array $options An associated array of options, see the {@tutorial connector.pkg#options.element}.
  368.      * @return bool true if the transaction was successfully begun, false otherwise.
  369.      */
  370.     
  371.     public function transaction($options array())
  372.     {
  373.         if($this->lookup(self::LOG_DEBUG$options))
  374.         {
  375.             $log "PdoConnector debug: Begin transaction in ";
  376.             error_log($log.$_SERVER["SCRIPT_FILENAME"]);
  377.         }
  378.         if($this->conn->beginTransaction())
  379.         {
  380.             return true;
  381.         }
  382.         else if($this->lookup(self::LOG_ERROR$options))
  383.         {
  384.             $log "PdoConnector error: Begin transaction in ";
  385.             error_log($log.$_SERVER["SCRIPT_FILENAME"]);
  386.             error_log("PdoConnector error: ".sqlsrv_errors());
  387.         }
  388.     }
  389.     
  390.     ///////////////////////////////////////////////////////////////////////////
  391.     /**
  392.      * Commits the current transaction on the current connection.
  393.      * The current transaction includes all statements on the connection that
  394.      * were executed after the call to transaction() and before any calls
  395.      * to rollback() or commit().
  396.      *
  397.      * @see IConnector::commit().
  398.      * @param array $options An associated array of options, see the {@tutorial connector.pkg#options.element}.
  399.      * @return bool true if the transaction was successfully committed, false otherwise.
  400.      */
  401.     
  402.     public function commit($options array())
  403.     {
  404.         if($this->lookup(self::LOG_DEBUG$options))
  405.         {
  406.             $log "PdoConnector debug: Commit in ";
  407.             error_log($log.$_SERVER["SCRIPT_FILENAME"]);
  408.         }
  409.         if($this->conn->commit())
  410.         {
  411.             return true;
  412.         }
  413.         else if($this->lookup(self::LOG_ERROR$options))
  414.         {
  415.             $log "PdoConnector error: Commit in ";
  416.             error_log($log.$_SERVER["SCRIPT_FILENAME"]);
  417.             error_log("PdoConnector error: ".sqlsrv_errors());
  418.         }
  419.     }
  420.     
  421.     ///////////////////////////////////////////////////////////////////////////
  422.     /**
  423.      * Rolls back the current transaction on the current connection.
  424.      * The current transaction includes all statements on the connection that
  425.      * were executed after the call to transaction() and before any calls
  426.      * to rollback() or commit().
  427.      *
  428.      * @see IConnector::rollback().
  429.      * @param array $options An associated array of options, see the {@tutorial connector.pkg#options.element}.
  430.      * @return bool true if the transaction was successfully rolled back, false otherwise.
  431.      */
  432.     
  433.     public function rollback($options array())
  434.     {
  435.         if($this->lookup(self::LOG_DEBUG$options))
  436.         {
  437.             $log "PdoConnector debug: Rollback in ";
  438.             error_log($log.$_SERVER["SCRIPT_FILENAME"]);
  439.         }
  440.         if($this->conn->rollBack())
  441.         {
  442.             return true;
  443.         }
  444.         else if($this->lookup(self::LOG_ERROR$options))
  445.         {
  446.             $log "PdoConnector error: Rollback in ";
  447.             error_log($log.$_SERVER["SCRIPT_FILENAME"]);
  448.             error_log("PdoConnector error: ".sqlsrv_errors());
  449.         }
  450.     }
  451.     
  452.     ///////////////////////////////////////////////////////////////////////////
  453.     /**
  454.      * Add a TOP x statement to a SQL SELECT query when the
  455.      * {@link IConnector::RESULT_LENGTH} is set.
  456.      *
  457.      * @param string $query A SQL query to execute on a database.
  458.      * @param array $options An associated array of options.
  459.      * @return string A modified SQL query.
  460.      */
  461.  
  462.     protected function build($query$options array())
  463.     {
  464.         $driver $this->conn->getAttribute(PDO::ATTR_DRIVER_NAME);
  465.         $offset $this->lookup(self::RESULT_OFFSET$options0);
  466.         $length $this->lookup(self::RESULT_LENGTH$options);
  467.                 
  468.         switch($driver)
  469.         {
  470.             case "odbc":
  471.             case "mssql"if(is_int($length))
  472.             {
  473.                 $number $offset $length;
  474.                 $pattern "/\A(SELECT)([\s]+(ALL|DISTINCT))?\b/i";
  475.                 $query preg_replace($pattern"$0 TOP {$number}"$query);
  476.             }
  477.             break;
  478.             case "mysql"if($offset || is_int($length))
  479.             {
  480.                 if(is_null($length)) $length PHP_INT_MAX;
  481.                 $query.= LB."LIMIT  {$offset}, {$length}";
  482.             }
  483.             break;
  484.         }
  485.         return $query;
  486.     }
  487.  
  488.     ///////////////////////////////////////////////////////////////////////////
  489.     /**
  490.      * Bind values to a prepared statement using named or numeric parameters.
  491.      *
  492.      * @param PDOStatement $stmt The prepared statement.
  493.      * @param array $stack A numeric or associated array of parameter values.
  494.      * @param array $options An associated array of options.
  495.      * @return void 
  496.      */
  497.  
  498.     protected function bindStatement($stmt$stack$options array())
  499.     {
  500.         $named $this->lookup(self::PARAM_NAMED$options);
  501.         $prefix $this->lookup(self::PARAM_PREFIX$options);
  502.  
  503.         foreach($stack as $name => $value)
  504.         {
  505.             $index $named $prefix.$name $name 1;
  506.  
  507.             switch(gettype($value))
  508.             {
  509.                 case "NULL"$stmt->bindValue($index$valuePDO::PARAM_NULL)break;
  510.                 case "boolean"$stmt->bindValue($index$valuePDO::PARAM_BOOL)break;
  511.                 case "integer"$stmt->bindValue($index$valuePDO::PARAM_INT)break;
  512.                 default$stmt->bindValue($index$value)break;
  513.             }
  514.         }
  515.     }
  516.  
  517.     ///////////////////////////////////////////////////////////////////////////
  518.     /**
  519.      * Fetch multiple rows of a query result.
  520.      *
  521.      * If the {@link IConnector::RESULT_LENGTH} or {@link IConnector::RESULT_OFFSET}
  522.      * options are set, some rows are omitted from the beginning and/or the end
  523.      * of the query result.
  524.      * If the {@link IConnector::RESULT_KEY_FIELD} option is set, the
  525.      * resulting table is an <b>associated</b> array of rows.
  526.      *
  527.      * @param resource $stmt A statement resource corresponding to an executed statement.
  528.      * @param array $options An associated array of options.
  529.      * @return array The query result as a table (array of associated arrays).
  530.      */
  531.  
  532.     protected function fetch($stmt$options array())
  533.     {
  534.         $key $this->lookup(self::RESULT_KEY_FIELD$options);
  535.         $offset $this->lookup(self::RESULT_OFFSET$options0);
  536.         $length $this->lookup(self::RESULT_LENGTH$options);
  537.                  
  538.         $number is_null($lengthPHP_INT_MAX $length $offset;
  539.         $table array();
  540.         $index 0;
  541.  
  542.         while($row $stmt->fetch(PDO::FETCH_ASSOC))
  543.         {
  544.             if($number <= $indexbreak;
  545.             if($offset $index++continue;
  546.             $row $this->strDecode($row$options);
  547.             $key $table[$row[$key]] $row $table[$row;
  548.         }
  549.         return $table;
  550.     }
  551.  
  552.     ///////////////////////////////////////////////////////////////////////////
  553. }
  554.  
  555. ?>

Documentation generated on Wed, 03 Jun 2009 12:41:55 +0200 by phpDocumentor 1.4.1