From 7b72b8ae3c3432e7d41987787709edadbdcbae0f Mon Sep 17 00:00:00 2001
From: Cyril Vazquez <cyril.vazquez@maarch.org>
Date: Tue, 30 Jun 2015 08:57:31 +0000
Subject: [PATCH] FEAT #2482 Class Database with PDO, used on
 ObjectCOntrollerAbstract

---
 .../core/class/ObjectControlerAbstract.php    |  12 +-
 core/trunk/core/class/class_db_pdo.php        | 205 +++++++++++-------
 2 files changed, 138 insertions(+), 79 deletions(-)

diff --git a/core/trunk/core/class/ObjectControlerAbstract.php b/core/trunk/core/class/ObjectControlerAbstract.php
index 1baa15942d6..b8a4c682762 100644
--- a/core/trunk/core/class/ObjectControlerAbstract.php
+++ b/core/trunk/core/class/ObjectControlerAbstract.php
@@ -298,22 +298,22 @@ abstract class ObjectControler
         require_once 'core/class/class_db_pdo.php';
         $database = new Database();
         $theQuery = "SELECT * FROM $table_name WHERE $table_id = :id " . $whereComp;
-        $database->query($theQuery);
-        $database->bind(':id', $id);
+        $queryParams = array(':id' => $id);
 
         if (count($params > 0)) {
             foreach ($params as $keyParam => $keyValue) {
-                $database->bind(":" . $keyParam, $keyValue);
+                $queryParams[":" . $keyParam] = $keyValue;
             }
         }
-        $database->execute();
+
+        $stmt = $database->query($theQuery, $queryParams);
         
-        if ($database->rowCount() == 0) {
+        if ($stmt->rowCount() == 0) {
             return null;
         } else {
             // Constructing result
             $object = new $object_name();
-            $rows = $database->resultset();    
+            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);    
             
             for ($cpt=0;$cpt<count($rows);$cpt++) {
                 foreach ($rows[$cpt] as $key => $value) {
diff --git a/core/trunk/core/class/class_db_pdo.php b/core/trunk/core/class/class_db_pdo.php
index 76d554eabc0..d69ec3034c3 100644
--- a/core/trunk/core/class/class_db_pdo.php
+++ b/core/trunk/core/class/class_db_pdo.php
@@ -1,22 +1,55 @@
 <?php
-
-class Database {
-
-    private $databasetype;
+/*
+ * Copyright (C) 2015 Maarch
+ *
+ * This file is part of Maarch.
+ *
+ * Maarch is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Maarch is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Maarch.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Class for database queries
+ * 
+ * @package Core
+ */
+class Database
+{
+    /**
+     * Prepared statements indexed by dsn and queryString
+     * @var array
+     */
+    private static $preparedStmt = array();
+
+    private $driver;
     private $server;
     private $port;
     private $user;
     private $password;
     private $database;
+    private $dsn;
  
-    private $dbh;
+    private $pdo;
+    
     private $error;
 
     private $stmt;
 
+    /**
+     * Constructor. Connects to the database if connection parameters are available in the session config 
+     */
     public function __construct()
     {
- 		if (isset($_SESSION['config']['databaseserver'])) {
+        if (isset($_SESSION['config']['databaseserver'])) {
             $this->server = $_SESSION['config']['databaseserver'];
         }
         if (isset($_SESSION['config']['databaseserverport'])) {
@@ -32,112 +65,138 @@ class Database {
             $this->database = $_SESSION['config']['databasename'];
         }
         if (isset($_SESSION['config']['databasetype'])) {
-            $this->databasetype = $_SESSION['config']['databasetype'];
-            if ($this->databasetype == 'POSTGRESQL') {
-                $this->databasetype = 'pgsql';
-            } elseif ($this->databasetype == 'MYSQL') {
-                $this->databasetype = 'mysql';
-            } elseif ($this->databasetype == 'ORACLE') {
-                $this->databasetype = 'oracle';
+            switch($_SESSION['config']['databasetype']) {
+                case 'POSTGRESQL': 
+                    $this->driver = 'pgsql';
+                    break;
+                case 'MYSQL': 
+                    $this->driver = 'mysql';
+                    break;
+
+                case 'ORACLE':
+                    $this->driver = 'oci';
+                    break;
+
+                default:
+                    print_r('DRIVER ERROR: Unknown database driver ' . $_SESSION['config']['databasetype']);
             }
         }
         
         // Set DSN
-        $dsn = $this->databasetype 
-        	. ':host=' . $this->server
-        	. ';port=' . $this->port
-        	. ';dbname=' . $this->database;
+        $this->dsn = $this->databasetype 
+            . ':host=' . $this->server
+            . ';port=' . $this->port
+            . ';dbname=' . $this->database
+        ;
+
+        if (!isset(self::$preparedStmt[$this->dsn])) {
+            self::$preparedStmt[$this->dsn] = array();
+        }
 
         // Set options
         $options = array (
             PDO::ATTR_PERSISTENT    => true,
-            PDO::ATTR_ERRMODE       => PDO::ERRMODE_EXCEPTION
+            PDO::ATTR_ERRMODE       => PDO::ERRMODE_EXCEPTION,
+            PDO::ATTR_CASE          => PDO::CASE_LOWER
         );
         // Create a new PDO instanace
         try {
-            $this->dbh = new PDO($dsn, $this->user, $this->password, $options);
-        }
-        // Catch any errors
-        catch (PDOException $e) {
-            $this->error = $e->getMessage();
+            $this->pdo = new PDO($this->dsn, $this->user, $this->password, $options);
+        } catch (PDOException $PDOException) {
+            $this->error = $PDOException->getMessage();
         }
 
         if ($this->error && $_SESSION['config']['debug'] == 'true') {
-        	print_r('SQL ERROR:' . $this->error);
+            print_r('SQL ERROR:' . $this->error);
         }
         
     }
 
-    public function query($query)
+    /**
+     * Begin a new transaction
+     * 
+     * @return bool
+     */
+    public function beginTransaction()
     {
-        $this->stmt = $this->dbh->prepare($query);
+        return $this->pdo->beginTransaction();
     }
 
-    public function bind($param, $value, $type = null)
+    /**
+     * Commit a transaction
+     * 
+     * @return bool
+     */
+    public function commit()
     {
-        if (is_null($type)) {
-            switch (true) {
-                case is_int($value):
-                    $type = PDO::PARAM_INT;
-                    break;
-                case is_bool($value):
-                    $type = PDO::PARAM_BOOL;
-                    break;
-                case is_null($value):
-                    $type = PDO::PARAM_NULL;
-                    break;
-                default:
-                    $type = PDO::PARAM_STR;
-            }
-        }
-        $this->stmt->bindValue($param, $value, $type);
+        return $this->pdo->commit();
     }
 
-    public function execute()
+    /**
+     * Rollback a transaction
+     * 
+     * @return bool
+     */
+    public function rollback()
     {
-        return $this->stmt->execute();
+        return $this->pdo->rollback();
     }
 
-    public function resultset() 
+    /**
+     * Check if in a transaction
+     * 
+     * @return bool
+     */
+    public function inTransaction()
     {
-        $this->execute();
-        return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
+        return $this->pdo->inTransaction();
     }
 
-    public function single()
+    /**
+     * Prepare a query and returns the statement.
+     * Save the prepared statement for a later execution with parameters
+     * @param string $queryString The SQL query string to prepare
+     * 
+     * @return PDOStatement
+     */
+    public function prepare($queryString)
     {
-        $this->execute();
-        return $this->stmt->fetch(PDO::FETCH_ASSOC);
-    }
+        if (!isset(self::$preparedStmt[$this->dsn][$queryString])) {
+            self::$preparedStmt[$this->dsn][$queryString] = $this->pdo->prepare($queryString);
+        }
 
-    public function rowCount()
-    {
-        return $this->stmt->rowCount();
+        return self::$preparedStmt[$this->dsn][$queryString];
     }
 
-    public function lastInsertId()
+    /**
+     * Prepare and execute a query. Returns the prepared and executed statement.
+     * Statement can be used to fetch resulting rows OR by a later call to a fetch method
+     * @param string $queryString     The SQL query string
+     * @param array  $parameters      An indexed or associative array of parameters
+     * @param bool   $catchExceptions Indicates wheter the PDO exceptions must be caught 
+     * 
+     * @return PDOStatement The prepared and executed statement
+     * 
+     * @throws PDOException If a PDO error occurs during preparation or execution
+     */
+    public function query($queryString, $parameters=null, $catchExceptions=false)
     {
-        return $this->dbh->lastInsertId();
-    }
+        try {
+            $this->stmt = $this->prepare($queryString);
 
-    public function beginTransaction()
-    {
-        return $this->dbh->beginTransaction();
-    }
+            $executed = $this->stmt->execute($parameters);
+        } catch (PDOException $PDOException) {
+            if ($catchExceptions) {
+                $this->error = $PDOException->getMessage();
 
-    public function endTransaction()
-    {
-        return $this->dbh->commit();
-    }
+                return false;
+            } else {
+                throw $PDOException;
+            }
+        }
 
-    public function cancelTransaction()
-    {
-        return $this->dbh->rollBack();
+        return $this->stmt;
     }
 
-    public function debugDumpParams()
-    {
-	    return $this->stmt->debugDumpParams();
-    }
 }
 
-- 
GitLab