dblayer : add more debug
dblayer : add more unit tests (foreign keys) dblayer : add the same answer when updating a line with the same informations dblayer : better support of foreign keys git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@1842 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
@@ -39,20 +39,22 @@ class test_dblayer_{ENGINE} extends PHPUnit_Framework_TestCase
|
||||
$dbconfig = $this->confs["{ENGINE}"];
|
||||
$db = new dblayer ($dbconfig["dsn"], $dbconfig["username"],
|
||||
$dbconfig["password"], $dbconfig["driver_options"]);
|
||||
$db->table = "grouped";
|
||||
try
|
||||
foreach (array ("users", "grouped") as $table)
|
||||
{
|
||||
$res = $db->dropTable();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
|
||||
$db->table = $table;
|
||||
try
|
||||
{
|
||||
$res = $db->dropTable();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
// Never generate an error, just drop the table if it exists, and do noting
|
||||
// if it doesn't exists
|
||||
}
|
||||
|
||||
public function test_createTable ()
|
||||
public function test_createTable1 ()
|
||||
{
|
||||
// Create a table named group
|
||||
$dbconfig = $this->confs["{ENGINE}"];
|
||||
@@ -63,11 +65,13 @@ class test_dblayer_{ENGINE} extends PHPUnit_Framework_TestCase
|
||||
"object"=>array ("varchar", "255", "not null"),
|
||||
"where"=>array ("varchar", "255", "not null"),
|
||||
"with space"=>array ("varchar", "255", "not null"));
|
||||
$db->unique = array ();
|
||||
$db->primary = "group";
|
||||
$res = $db->createTable ();
|
||||
$this->assertSame (0, $res);
|
||||
}
|
||||
|
||||
public function test_insert ()
|
||||
public function test_insert1 ()
|
||||
{
|
||||
$dbconfig = $this->confs["{ENGINE}"];
|
||||
$db = new dblayer ($dbconfig["dsn"], $dbconfig["username"],
|
||||
@@ -78,6 +82,7 @@ class test_dblayer_{ENGINE} extends PHPUnit_Framework_TestCase
|
||||
"where"=>array ("varchar", "255", "not null"),
|
||||
"with space"=>array ("varchar", "255", "not null"));
|
||||
$db->unique = array ();
|
||||
$db->primary = "group";
|
||||
$res = $db->insert (array ("group"=>"gr ou\"p",
|
||||
"object"=>"/éobj%",
|
||||
"where"=>"\$'\"",
|
||||
@@ -198,10 +203,60 @@ class test_dblayer_{ENGINE} extends PHPUnit_Framework_TestCase
|
||||
"with space"=>array ("varchar", "255", "not null"));
|
||||
$db->unique = array ("group");
|
||||
$db->primary = "group";
|
||||
// Update primary key with primary key in unique
|
||||
// Update primary key with primary key in unique with same values to test if
|
||||
// the exception is NOT raised
|
||||
$res = $db->update ("NEW GROUP", array ("group"=>"NEW GROUP",
|
||||
"object"=>"%éàoppp",
|
||||
"with space"=>"WITH SPACE"));
|
||||
// SQLite and PostgreSQL return 1 line modified
|
||||
// MySQL return 0 by default because there is no modification on the line
|
||||
// http://fr2.php.net/manual/en/pdostatement.rowcount.php#104930
|
||||
// Now, the MYSQL_ATTR_FOUND_ROWS is added to connection to be the same in
|
||||
// all the engines
|
||||
$this->assertSame (1, $res);
|
||||
}
|
||||
|
||||
// Part to test the foreign keys
|
||||
public function test_createTable2 ()
|
||||
{
|
||||
// Create a table named group
|
||||
$dbconfig = $this->confs["{ENGINE}"];
|
||||
$db = new dblayer ($dbconfig["dsn"], $dbconfig["username"],
|
||||
$dbconfig["password"], $dbconfig["driver_options"]);
|
||||
$db->table = "users";
|
||||
$db->fields = array ("user"=>array ("varchar", "255", "not null"),
|
||||
"groupmember"=>array ("varchar", "255", "not null"),
|
||||
"where"=>array ("varchar", "255", "not null"),
|
||||
"with space"=>array ("varchar", "255", "not null"));
|
||||
$db->foreign = array (
|
||||
"groupmember"=>array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"),
|
||||
);
|
||||
|
||||
$res = $db->createTable ();
|
||||
$this->assertSame (0, $res);
|
||||
}
|
||||
|
||||
public function test_insert2 ()
|
||||
{
|
||||
$dbconfig = $this->confs["{ENGINE}"];
|
||||
$db = new dblayer ($dbconfig["dsn"], $dbconfig["username"],
|
||||
$dbconfig["password"], $dbconfig["driver_options"]);
|
||||
$db->table = "users";
|
||||
$db->fields = array ("user"=>array ("varchar", "255", "not null"),
|
||||
"groupmember"=>array ("varchar", "255", "not null"),
|
||||
"where"=>array ("varchar", "255", "not null"),
|
||||
"with space"=>array ("varchar", "255", "not null"));
|
||||
$db->unique = array ("user");
|
||||
$db->primary = "user";
|
||||
$db->foreign = array (
|
||||
"groupmember"=>array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"),
|
||||
);
|
||||
$res = $db->insert (array ("user"=>"Us ou\"r",
|
||||
"groupmember"=>"NEW GROUP",
|
||||
"where"=>"\$'\"",
|
||||
"with space"=>"with space"));
|
||||
// SQLite start at 1, MySQL start at 0...
|
||||
$this->assertThat($res, $this->lessThanOrEqual(2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
123
dblayer.php
123
dblayer.php
@@ -9,9 +9,9 @@
|
||||
The dbLayer provide an abstraction layer on PDO to be easier on all the CRUD
|
||||
(Create, Read, Update, Delete) operations, accross all the databases engines.
|
||||
To use it, extends in your code this class, and define the attributes :
|
||||
- protected $table : name of the table you want to use
|
||||
- protected $fields : description of all the fields in the database like :
|
||||
protected $fields = array (
|
||||
- public $table : name of the table you want to use
|
||||
- public $fields : description of all the fields in the database like :
|
||||
public $fields = array (
|
||||
"id"=>array ("integer", "not null", "autoincrement"),
|
||||
"zone"=>array ("varchar", "255", "not null"),
|
||||
"viewname"=>array ("varchar", "255"),
|
||||
@@ -20,12 +20,17 @@ To use it, extends in your code this class, and define the attributes :
|
||||
"opendate"=>array ("datetime", "not null"),
|
||||
"closedate"=>array ("datetime"),
|
||||
);
|
||||
- protected $primary = "id" ; the primary key of the table (in text). Actually
|
||||
- public $primary = "id" ; the primary key of the table (in text). Actually
|
||||
the dbLayer abstraction don't supports primary key on multiples columns
|
||||
- protected $unique = array ("column", array ("column1", "column2");)
|
||||
- public $unique = array ("column", array ("column1", "column2");)
|
||||
- public $foreign : Add the support of foreign keys. Must be defined like :
|
||||
public $foreign = array (
|
||||
"localfield"=>array ("foreign Table", "foreign key",
|
||||
"ON UPDATE CASCADE ON DELETE CASCADE"),
|
||||
);
|
||||
|
||||
Optionnaly, you can add the
|
||||
- protected $debug = TRUE : enable the debug on screen (NOT FOR PROD !!)
|
||||
- public $debug = TRUE : enable the debug on screen (NOT FOR PROD !!)
|
||||
*/
|
||||
|
||||
require_once ("domframework/verify.php");
|
||||
@@ -89,20 +94,23 @@ class dblayer extends PDO
|
||||
public function __construct ($dsn, $username=null, $password=null,
|
||||
$driver_options=null)
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->db = new PDO ($dsn, $username, $password, $driver_options);
|
||||
$this->db->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception ("PDO error : ".$e->getMessage(), 500);
|
||||
}
|
||||
|
||||
$driver = @explode (":", $dsn);
|
||||
if (! isset ($driver[0]))
|
||||
throw new Exception (_("No valid DSN provided"), 500);
|
||||
// Force specifics initialisations
|
||||
switch ($this->db->getAttribute(PDO::ATTR_DRIVER_NAME))
|
||||
switch ($driver[0])
|
||||
{
|
||||
case "sqlite":
|
||||
try
|
||||
{
|
||||
$this->db = new PDO ($dsn, $username, $password, $driver_options);
|
||||
$this->db->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception ("PDO error : ".$e->getMessage(), 500);
|
||||
}
|
||||
|
||||
// Look at the right to write in database and in the directory
|
||||
$file = substr ($dsn, 7);
|
||||
if (! is_writeable (dirname ($file)))
|
||||
@@ -121,11 +129,32 @@ class dblayer extends PDO
|
||||
$this->sep = "`";
|
||||
break;
|
||||
case "mysql":
|
||||
try
|
||||
{
|
||||
$driver_options[PDO::MYSQL_ATTR_FOUND_ROWS] = 1;
|
||||
$this->db = new PDO ($dsn, $username, $password, $driver_options);
|
||||
$this->db->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception ("PDO error : ".$e->getMessage(), 500);
|
||||
}
|
||||
|
||||
// Set the coding to UTF8
|
||||
$this->db->exec("SET CHARACTER SET utf8");
|
||||
$this->sep = "`";
|
||||
break;
|
||||
case "pgsql":
|
||||
try
|
||||
{
|
||||
$this->db = new PDO ($dsn, $username, $password, $driver_options);
|
||||
$this->db->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception ("PDO error : ".$e->getMessage(), 500);
|
||||
}
|
||||
|
||||
// Set the coding to UTF8
|
||||
$this->db->exec("SET NAMES 'utf8'");
|
||||
$this->sep = "\"";
|
||||
@@ -202,9 +231,11 @@ class dblayer extends PDO
|
||||
*/
|
||||
public function verify ($datas, $updatekey=false)
|
||||
{
|
||||
if ($this->debug) echo "== Entering verify\n";
|
||||
$errors = array ();
|
||||
foreach ($this->fields as $key=>$params)
|
||||
{
|
||||
if ($this->debug) echo " verify ($key)\n";
|
||||
if ($updatekey === false)
|
||||
{
|
||||
// Don't check if there is an update : the database is already filled
|
||||
@@ -311,6 +342,7 @@ class dblayer extends PDO
|
||||
if (count ($errors) !== 0)
|
||||
return $errors;
|
||||
|
||||
if ($this->debug) echo " verify inconsistency\n";
|
||||
// Check for inconsistency
|
||||
$verify = $this->verifyAll ($datas);
|
||||
if (count ($verify))
|
||||
@@ -325,6 +357,7 @@ class dblayer extends PDO
|
||||
|
||||
if ($updatekey !== false)
|
||||
{
|
||||
if ($this->debug) echo " verify in updatekey\n";
|
||||
// Check if the unique constrain is valid before doing the insertion
|
||||
// 1. Read the actual state
|
||||
$before = $this->read (array (array ($this->primary, $updatekey)));
|
||||
@@ -339,14 +372,22 @@ class dblayer extends PDO
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->debug) echo " verify NO updatekey\n";
|
||||
$after = $datasOK;
|
||||
}
|
||||
// Check if the unique constrain is valid before doing the insertion
|
||||
foreach ($this->unique as $columns)
|
||||
foreach ($this->unique as $k=>$columns)
|
||||
{
|
||||
if ($this->primary === null)
|
||||
{
|
||||
return array (dgettext("domframework",
|
||||
"No field primary defined for tests in primary"));
|
||||
}
|
||||
|
||||
if (is_array ($columns))
|
||||
{
|
||||
// Multiple columns in unique
|
||||
if ($this->debug) echo " verify unique multiple $k\n";
|
||||
$select = array ();
|
||||
if ($updatekey !== false)
|
||||
$select[] = array ($this->primary, $updatekey, "!=");
|
||||
@@ -372,6 +413,7 @@ class dblayer extends PDO
|
||||
else
|
||||
{
|
||||
// One column in unique
|
||||
if ($this->debug) echo " verify unique one column $k\n";
|
||||
if (!array_key_exists ($columns, $after)) continue;
|
||||
$select = array ();
|
||||
if ($updatekey !== false)
|
||||
@@ -395,36 +437,49 @@ class dblayer extends PDO
|
||||
// Check if the foreign keys constrains are valid before doing the insertion
|
||||
foreach ($this->foreign as $foreign=>$data)
|
||||
{
|
||||
if ($this->debug) echo " verify foreign $foreign\n";
|
||||
if (! isset ($datas[$foreign]))
|
||||
{
|
||||
$errors[] = array ("error", sprintf (dgettext("domframework",
|
||||
"The foreign column '%s' is not provided"),
|
||||
$foreign));
|
||||
return $errors;
|
||||
}
|
||||
if (! isset ($datas[$foreign][0]))
|
||||
{
|
||||
$errors[] = array ("error", sprintf (dgettext("domframework",
|
||||
"The field type for column '%s' is not provided"),
|
||||
$foreign));
|
||||
return $errors;
|
||||
continue;
|
||||
}
|
||||
$table = $data[0];
|
||||
$column = $data[1];
|
||||
$req = "SELECT $column ".
|
||||
$req = "SELECT $this->sep$column$this->sep ".
|
||||
"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->db->prepare ($req);
|
||||
$val = $datas[$foreign];
|
||||
$key = $column;
|
||||
if ($this->debug) echo "DEBUG BIND : ".$this->fields[$foreign][0]."\n";
|
||||
if ($this->debug) echo "DEBUG BIND : $column(".md5 ($column)."->".
|
||||
var_export ($val, TRUE)."\n";
|
||||
if ($val === null)
|
||||
$st->bindValue (":".md5 ($key), $val, PDO::PARAM_NULL);
|
||||
elseif ($this->fields[$key][0] === "integer")
|
||||
elseif ($this->fields[$foreign][0] === "integer")
|
||||
$st->bindValue (":".md5 ($key), $val, PDO::PARAM_INT);
|
||||
elseif ($this->fields[$key][0] === "varchar")
|
||||
elseif ($this->fields[$foreign][0] === "varchar")
|
||||
$st->bindValue (":".md5 ($key), $val, PDO::PARAM_STR);
|
||||
elseif ($this->fields[$key][0] === "datetime")
|
||||
elseif ($this->fields[$foreign][0] === "datetime")
|
||||
$st->bindValue (":".md5 ($key), $val, PDO::PARAM_STR);
|
||||
elseif ($this->fields[$key][0] === "date")
|
||||
elseif ($this->fields[$foreign][0] === "date")
|
||||
$st->bindValue (":".md5 ($key), $val, PDO::PARAM_STR);
|
||||
else
|
||||
throw new Exception ("TO BE DEVELOPPED : ".$this->fields[$key][0], 500);
|
||||
{
|
||||
throw new Exception ("TO BE DEVELOPPED : ".$this->fields[$foreign][0],
|
||||
500);
|
||||
}
|
||||
$st->execute ();
|
||||
$res = array ();
|
||||
while ($d = $st->fetch (PDO::FETCH_ASSOC))
|
||||
@@ -452,12 +507,16 @@ class dblayer extends PDO
|
||||
@param array $datas Datas to be recorded (column=>value)*/
|
||||
public function insert ($datas)
|
||||
{
|
||||
if ($this->debug) echo "== Entering insert\n";
|
||||
if ($this->db === null)
|
||||
throw new Exception (dgettext("domframework", "Database not connected"),
|
||||
500);
|
||||
if ($this->unique === null)
|
||||
throw new Exception (dgettext("domframework",
|
||||
"Unique fields of table are not defined"), 500);
|
||||
if (! is_array ($this->unique))
|
||||
throw new Exception (dgettext("domframework",
|
||||
"The unique configuration is not an array"), 500);
|
||||
if (!is_array ($datas))
|
||||
throw new Exception (dgettext("domframework",
|
||||
"The datas provided to create are not array"),
|
||||
@@ -472,7 +531,10 @@ class dblayer extends PDO
|
||||
$datasOK = array ();
|
||||
$errors = $this->verify ($datas);
|
||||
if (count ($errors) !== 0)
|
||||
throw new Exception (reset ($errors), 405);
|
||||
{
|
||||
$errors = reset ($errors);
|
||||
throw new Exception ($errors[1], 405);
|
||||
}
|
||||
foreach ($this->fields as $field=>$desc)
|
||||
{
|
||||
if (isset ($datas[$field]))
|
||||
@@ -527,6 +589,7 @@ class dblayer extends PDO
|
||||
public function read ($select=null, $display=null, $order=null,
|
||||
$whereOr=false)
|
||||
{
|
||||
if ($this->debug) echo "== Entering read\n";
|
||||
if ($this->db === null)
|
||||
throw new Exception (dgettext("domframework", "Database not connected"),
|
||||
500);
|
||||
@@ -638,9 +701,11 @@ 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)
|
||||
{
|
||||
if ($this->debug) echo "== Entering update\n";
|
||||
if ($this->db === null)
|
||||
throw new Exception (dgettext("domframework", "Database not connected"),
|
||||
500);
|
||||
@@ -652,7 +717,6 @@ class dblayer extends PDO
|
||||
$errors = $this->verify ($datas, $updatekey);
|
||||
if (count ($errors) !== 0)
|
||||
{
|
||||
$errors = reset ($errors);
|
||||
throw new Exception ($errors[1], 405);
|
||||
}
|
||||
foreach ($this->fields as $field=>$desc)
|
||||
@@ -724,6 +788,7 @@ class dblayer extends PDO
|
||||
@param strin|integer $deletekey The key of primary key to be deleted */
|
||||
public function delete ($deletekey)
|
||||
{
|
||||
if ($this->debug) echo "== Entering delete\n";
|
||||
if ($this->db === null)
|
||||
throw new Exception (dgettext("domframework", "Database not connected"));
|
||||
$req = "DELETE FROM $this->sep$this->tableprefix$this->table$this->sep ";
|
||||
@@ -740,6 +805,7 @@ class dblayer extends PDO
|
||||
/** Translation of fields */
|
||||
public function titles ()
|
||||
{
|
||||
if ($this->debug) echo "== Entering titles\n";
|
||||
if (count ($this->fields) === 0)
|
||||
throw new Exception (dgettext("domframework", "No Field defined"), 500);
|
||||
$arr = array ();
|
||||
@@ -759,6 +825,7 @@ class dblayer extends PDO
|
||||
/** Drop the table */
|
||||
public function dropTable ()
|
||||
{
|
||||
if ($this->debug) echo "== Entering dropTables\n";
|
||||
if ($this->db === null)
|
||||
throw new Exception (dgettext("domframework", "Database not connected"));
|
||||
$sql = "DROP TABLE $this->sep$this->tableprefix$this->table$this->sep";
|
||||
@@ -785,6 +852,7 @@ class dblayer extends PDO
|
||||
*/
|
||||
public function createTable ()
|
||||
{
|
||||
if ($this->debug) echo "== Entering createTable\n";
|
||||
if ($this->db === null)
|
||||
throw new Exception (dgettext("domframework", "Database not connected"),
|
||||
500);
|
||||
@@ -1089,6 +1157,7 @@ class dblayer extends PDO
|
||||
Return the an array with the datas */
|
||||
public function directRead ($sql)
|
||||
{
|
||||
if ($this->debug) echo "== Entering directRead\n";
|
||||
$st = $this->db->prepare ($sql);
|
||||
$st->execute ();
|
||||
$res = array ();
|
||||
|
||||
Reference in New Issue
Block a user