diff --git a/dblayer.php b/dblayer.php index 4b86e45..1643c27 100644 --- a/dblayer.php +++ b/dblayer.php @@ -36,7 +36,7 @@ Optionnaly, you can add the require_once ("domframework/verify.php"); /** Permit abstraction on the differents SQL databases available */ -class dblayer extends PDO +class dblayer { /** The table name to use */ public $table = null; @@ -84,7 +84,8 @@ class dblayer extends PDO the table, and re-import the datas (http://www.sqlite.org/omitted.html) */ /** Limit to one instance of the connection to the same database */ - private static $instance = null; + // Based on an idea of http://tonylandis.com/php/php5-pdo-singleton-class/ + private static $instance = array (); /** Connection to the database engine See http://fr2.php.net/manual/en/pdo.construct.php for the $dsn format @@ -99,6 +100,7 @@ class dblayer extends PDO if (! isset ($driver[0])) throw new Exception (_("No valid DSN provided"), 500); // Force specifics initialisations + $this->dsn = $dsn; switch ($driver[0]) { case "sqlite": @@ -116,56 +118,76 @@ class dblayer extends PDO file_exists ($file) && fileowner ($file) === posix_getuid ()) chmod ($file, 0666); - try + // Print the instances of PDO objects stored : + // var_dump (self::$instance); + if (! array_key_exists ($this->dsn, self::$instance)) { - parent::__construct ($dsn, $username, $password, $driver_options); - parent::setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - } - catch (Exception $e) - { - throw new Exception ("PDO error : ".$e->getMessage(), 500); + if ($this->debug) echo "CONNECT TO DATABASE\n"; + try + { + self::$instance[$this->dsn] = new PDO ($dsn, $username, $password, + $driver_options); + self::$instance[$this->dsn]->setAttribute (PDO::ATTR_ERRMODE, + PDO::ERRMODE_EXCEPTION); + } + catch (Exception $e) + { + throw new Exception ("PDO error : ".$e->getMessage(), 500); + } } // Force ForeignKeys support (disabled by default) - $this->exec("PRAGMA foreign_keys = ON"); + self::$instance[$this->dsn]->exec ("PRAGMA foreign_keys = ON"); $this->sep = "`"; break; case "mysql": - try + if (! array_key_exists ($this->dsn, self::$instance)) { - $driver_options[PDO::MYSQL_ATTR_FOUND_ROWS] = 1; - parent::__construct ($dsn, $username, $password, $driver_options); - parent::setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - } - catch (Exception $e) - { - throw new Exception ("PDO error : ".$e->getMessage(), 500); + if ($this->debug) echo "CONNECT TO DATABASE\n"; + try + { + $driver_options[PDO::MYSQL_ATTR_FOUND_ROWS] = 1; + self::$instance[$this->dsn] = new PDO ($dsn, $username, $password, + $driver_options); + self::$instance[$this->dsn]->setAttribute (PDO::ATTR_ERRMODE, + PDO::ERRMODE_EXCEPTION); + } + catch (Exception $e) + { + throw new Exception ("PDO error : ".$e->getMessage(), 500); + } } // Set the coding to UTF8 - $this->exec("SET CHARACTER SET utf8"); + self::$instance[$this->dsn]->exec ("SET CHARACTER SET utf8"); $this->sep = "`"; break; case "pgsql": - try + if (! array_key_exists ($this->dsn, self::$instance)) { - parent::__construct ($dsn, $username, $password, $driver_options); - parent::setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - } - catch (Exception $e) - { - throw new Exception ("PDO error : ".$e->getMessage(), 500); + if ($this->debug) echo "CONNECT TO DATABASE\n"; + try + { + self::$instance[$this->dsn] = new PDO ($dsn, $username, $password, + $driver_options); + self::$instance[$this->dsn]->setAttribute (PDO::ATTR_ERRMODE, + PDO::ERRMODE_EXCEPTION); + } + catch (Exception $e) + { + throw new Exception ("PDO error : ".$e->getMessage(), 500); + } } // Set the coding to UTF8 - $this->exec("SET NAMES 'utf8'"); + self::$instance[$this->dsn]->exec ("SET NAMES 'utf8'"); $this->sep = "\""; break; default: throw new Exception (dgettext("domframework", "Unknown PDO driver provided"), 500); } - $this->dsn = $dsn; + return self::$instance[$this->dsn]; } /** Return the connected database name from DSN used to connect */ @@ -192,11 +214,11 @@ class dblayer extends PDO if ($this->sep === "") throw new Exception (dgettext("domframework", "Database not connected"), 500); - switch ($this->getAttribute(PDO::ATTR_DRIVER_NAME)) + switch (self::$instance[$this->dsn]->getAttribute(PDO::ATTR_DRIVER_NAME)) { case "sqlite": $req = "SELECT name FROM sqlite_master WHERE type='table'"; - $st = $this->prepare ($req); + $st = self::$instance[$this->dsn]->prepare ($req); $st->execute (); $res = array (); while ($d = $st->fetch (PDO::FETCH_ASSOC)) @@ -206,7 +228,7 @@ class dblayer extends PDO $req = "SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA='".$this->databasename()."'"; - $st = $this->prepare ($req); + $st = self::$instance[$this->dsn]->prepare ($req); $st->execute (); $res = array (); while ($d = $st->fetch (PDO::FETCH_ASSOC)) @@ -216,7 +238,7 @@ class dblayer extends PDO $req = "SELECT * FROM pg_tables WHERE schemaname = 'public'"; - $st = $this->prepare ($req); + $st = self::$instance[$this->dsn]->prepare ($req); $st->execute (); $res = array (); while ($d = $st->fetch (PDO::FETCH_ASSOC)) @@ -230,7 +252,7 @@ class dblayer extends PDO } /** Verify if the provided datas can be inserted/updated in the database. - @param $datas An array containing the datas to verify with keys + @param $datas An array containing the datas to verify with keys @param $updatekey the key to update @return an array with the errors in array($key=>array($priority,$message)) */ @@ -275,7 +297,7 @@ class dblayer extends PDO //." ". dgettext("domframework","in")." ".$key); continue; } - + // Check for type inconsistencies if the value is provided if (is_null ($datas[$key])) { @@ -286,7 +308,7 @@ class dblayer extends PDO { $errors[$key] = array ("error", sprintf ( dgettext("domframework", - "Errors in consistency : '%s' is not an integer or a string [is %s]"), + "Errors in consistency : '%s' is not an integer or a string [is %s]"), $key, gettype ($datas[$key]))); continue; } @@ -400,12 +422,12 @@ class dblayer extends PDO $this->unique = array ($this->primary); // TODO : If Unique is not defined nor primary // FIXME : If unique is defined, could I test if the primary key is defined - // in a parameter of the unique and if it is not add it automatically + // in a parameter of the unique and if it is not add it automatically foreach ($this->unique as $k=>$columns) { if ($this->primary === null) { - return array (dgettext("domframework", + return array (dgettext("domframework", "No field primary defined for tests in primary")); } @@ -491,7 +513,7 @@ class dblayer extends PDO "FROM $this->sep$this->tableprefix$table$this->sep ". "WHERE $this->sep$column$this->sep=:".md5 ($column); if ($this->debug) echo "DEBUG : $req\n"; - $st = $this->prepare ($req); + $st = self::$instance[$this->dsn]->prepare ($req); $val = $datas[$foreign]; $key = $column; if ($this->debug) echo "DEBUG BIND : ".$this->fields[$foreign][0]."\n"; @@ -584,7 +606,7 @@ class dblayer extends PDO $req .= " VALUES "; $req .= "(:".implode (",:", $binds).")"; if ($this->debug) echo "DEBUG : $req\n"; - $st = $this->prepare ($req); + $st = self::$instance[$this->dsn]->prepare ($req); foreach ($datasOK as $key=>$val) { if ($this->debug) echo "DEBUG BIND : $key(".md5 ($key).")->". @@ -612,7 +634,7 @@ class dblayer extends PDO echo "dblayer execute exception : ".$e->getMessage()."\n"; exit; } - $lastID = $this->lastInsertId(); + $lastID = self::$instance[$this->dsn]->lastInsertId(); $lastID = $this->hookpostinsert ($datasOK, $lastID); return $lastID; } @@ -741,13 +763,13 @@ class dblayer extends PDO if ($this->debug) echo "DEBUG : $req\n"; try { - $st = $this->prepare ($req); + $st = self::$instance[$this->dsn]->prepare ($req); } catch (Exception $e) { if ($this->debug) echo "DEBUG : PREPARE ERROR ! Return FALSE". $e->getMessage()."\n"; - throw new Exception ($e->getMessage(), 500); + throw new Exception ($e->getMessage(), 500); } if ($select !== NULL) @@ -784,7 +806,7 @@ class dblayer extends PDO Return the number of rows modified @param string|integer $updatekey The key applied on primary key to be updated - @param array $datas The values to be updated + @param array $datas The values to be updated @return the number of lines modified */ public function update ($updatekey, $datas) { @@ -826,7 +848,7 @@ class dblayer extends PDO $req .= " WHERE $this->sep$this->primary$this->sep=:". md5 ("PRIMARY".$this->primary); if ($this->debug) echo "DEBUG : $req\n"; - $st = $this->prepare ($req); + $st = self::$instance[$this->dsn]->prepare ($req); // Add the primary key to field list temporaly. It will permit to update the // primary key $fields = $this->fields; @@ -886,7 +908,7 @@ class dblayer extends PDO $deletekey = $this->hookpredelete ($deletekey); $req = "DELETE FROM $this->sep$this->tableprefix$this->table$this->sep "; $req .= "WHERE $this->primary = :primary"; - $st = $this->prepare ($req); + $st = self::$instance[$this->dsn]->prepare ($req); if ($this->debug) echo "DEBUG : $req\n"; if ($this->debug) echo "DEBUG BIND : primary->". var_export ($deletekey, TRUE)."\n"; @@ -926,7 +948,7 @@ class dblayer extends PDO $sql = "DROP TABLE $this->sep$this->tableprefix$this->table$this->sep"; if ($this->debug) echo "$sql\n"; - return $this->exec($sql); + return self::$instance[$this->dsn]->exec ($sql); } /** Create the table defined by the differents fields. @@ -953,7 +975,7 @@ class dblayer extends PDO 500); if (count ($this->fields) === 0) throw new Exception (dgettext("domframework", "No Field defined"), 500); - switch ($this->getAttribute(PDO::ATTR_DRIVER_NAME)) + switch (self::$instance[$this->dsn]->getAttribute(PDO::ATTR_DRIVER_NAME)) { case "sqlite": $sql = "CREATE TABLE IF NOT EXISTS ". @@ -1248,7 +1270,7 @@ class dblayer extends PDO if ($this->debug) echo "$sql\n"; - return $this->exec($sql); + return self::$instance[$this->dsn]->exec ($sql); } /** This function permit to send a SQL request to the database to do a SELECT @@ -1256,7 +1278,7 @@ class dblayer extends PDO public function directRead ($sql) { if ($this->debug) echo "== Entering directRead\n"; - $st = $this->prepare ($sql); + $st = self::$instance[$this->dsn]->prepare ($sql); $st->execute (); $res = array (); while ($d = $st->fetch (PDO::FETCH_ASSOC)) @@ -1264,9 +1286,40 @@ class dblayer extends PDO return $res; } + /** This function disconnect the database. It is normally only used in phpunit + unit tests */ + public function disconnect () + { + unset (self::$instance[$this->dsn]); + } + + /** The prepare method */ + public function prepare ($statement, $driver_options = array()) + { + return self::$instance[$this->dsn]->prepare ($statement, $driver_options); + } + + /** Start a new Transaction */ + public function beginTransaction () + { + return self::$instance[$this->dsn]->beginTransaction (); + } + + /** Commit (validate) a transaction */ + public function commit () + { + return self::$instance[$this->dsn]->commit (); + } + + /** RollBack a transaction */ + public function rollback () + { + return self::$instance[$this->dsn]->rollback (); + } + /** Hook preinsert - This hook is run before inserting a new data in the database, after the - verification + This hook is run before inserting a new data in the database, after the + verification @param array the data to insert in the database @return the modified datas */ public function hookpreinsert ($data) @@ -1283,8 +1336,8 @@ class dblayer extends PDO } /** Hook preupdate - This hook is run before updating a data in the database, after the - verification + This hook is run before updating a data in the database, after the + verification @return the modified datas */ public function hookpreupdate ($updatekey, $data) {