diff --git a/DbCriteria.php b/DbCriteria.php new file mode 100644 index 0000000..287c4de --- /dev/null +++ b/DbCriteria.php @@ -0,0 +1,10 @@ +_expression = $expression; + } + public function __toString() { + return (string)$this->_expression; + } +} diff --git a/DbQueryBuilder.php b/DbQueryBuilder.php new file mode 100644 index 0000000..5fef41c --- /dev/null +++ b/DbQueryBuilder.php @@ -0,0 +1,44 @@ +_schema = sprintf('`%s`', (string)$schema); + return $this; + } + + public function setTable($table) { + $this->_table = sprintf('`%s`', (string)$table); + return $this; + } + + public function insert($params) { + $template = 'INSERT INTO %s (%s) VALUES (%s)'; + $dest = implode('.', array($this->_schema, $this->_table)); + $keys = $values = array(); + foreach ($params as $key => $param) { + $keys[] = sprintf('`%s`', $key); + if ($param instanceof DbExpression) { + $values[] = $param; + } + else { + $placeholder = sprintf(':%s', $key); + $values[] = sprintf(':%s', $key); + $this->_bind_params[$placeholder] = $param; + } + } + return sprintf($template, $dest, implode(', ', $keys), implode(', ', $values)); + } + + public function update() { + } + + public function getBindParams() { + return $this->_bind_params; + } +} diff --git a/Model.php b/Model.php index ab00394..71e7d57 100644 --- a/Model.php +++ b/Model.php @@ -10,10 +10,14 @@ require_once 'db.php'; require_once 'ModelException.php'; +require_once 'DbExpression.php'; +require_once 'DbQueryBuilder.php'; abstract class Model { private $_dbh; + private $_error_info; + private $_queryBuilder; // DbQueryBuilder instance private $_is_new_instance = true; private $_a = array(); // attributes @@ -24,6 +28,7 @@ abstract class Model { * @TODO Model::getByPK(array('id1' => 10, 'id2' => 20)) or just array(10,20) */ protected $_pk = 'id'; + protected $_schema = 'id'; protected $_table = 'id'; /** @@ -38,6 +43,8 @@ abstract class Model { public function __construct() { global $dbh; $this->_dbh = $dbh; + $this->_queryBuilder = new DbQueryBuilder(); + $this->_queryBuilder->setTable($this->_table)->setSchema($this->_schema); // we need table if (empty($this->_table)) { @@ -49,43 +56,51 @@ public function __construct() { } private function formatValues($v) { - if (!isset($this->datefields[$v])) { - return ':'.$v; // bind + if ($v instanceof DbExpression) { + return $v; } else { - return $v; // as is e.g. NOW() + return ':'.$v; } } + private function formatKeys($k) { return '`'.$k.'`'; } + + private function filterDbExpressions($v) { + return !($v instanceof DbExpression); + } + public function save() { if ($this->isNewRecord()) { - $keys = array_keys($this->_a); - $values = array_map(create_function('$k', 'return ":".$k;'), array_keys($this->_a)); - $keys = implode(', ', array_map(array($this, 'formatKeys'), $keys)); - $values = implode(', ', array_map(array($this, 'formatValues'), array_keys($this->_a))); - $sql = 'INSERT INTO '.$this->_table.' ('.$keys.') VALUES ('.$values.')'; - $statement = $this->_dbh->prepare($sql); - $result = $statement->execute($this->_a); - echo 'params: '; - echo $statement->debugDumpParams(); - echo 'error info: '; - echo var_export($statement->errorInfo(),1); - echo '<<<<<<<<'; + + $query = $this->_queryBuilder->insert($this->_a); + $statement = $this->_dbh->prepare($query); + $result = $statement->execute($this->_queryBuilder->getBindParams()); + if ($result) { $this->_a[$this->_pk] = $this->_dbh->lastInsertId(); } } else { // update + $values = array_map(create_function('$k,$v', 'return $k."=:".$v;'), array_keys($this->_a), $this->_a); $sql = 'UPDATE '.$this->_table.' SET '.implode(', ', $values).' WHERE '.$this->_pk.' = '.$this->_a[$this->_pk]; $statement = $this->db->prepare($sql); $result = $statement->execute($this->_a); + + } + if (!$result) { + $this->_error_info = $this->_dbh->errorInfo(); } return $result; } + public function getErrorInfo() { + return $this->_error_info; + } + public function isNewRecord() { return !isset($this->_a[$this->_pk]); } diff --git a/ModelClass.php b/ModelClass.php index 2341b2e..9463138 100644 --- a/ModelClass.php +++ b/ModelClass.php @@ -6,7 +6,7 @@ require_once 'Model.php'; class ModelClass extends Model { - protected $_table = 'test.model_test'; + protected $_schema = 'test'; + protected $_table = 'model_test'; protected $_pk = 'id'; } - diff --git a/TODO b/TODO new file mode 100644 index 0000000..3ecc567 --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +Pick out all the Db* classes from here - they should remain as an independant project diff --git a/schema.sql b/schema.sql deleted file mode 100644 index 3448571..0000000 --- a/schema.sql +++ /dev/null @@ -1,30 +0,0 @@ -create database if not exists `test` default character set = utf8 default collate = utf8_general_ci; - -use `test`; - -create table if not exists `users` ( - `id` int(11) unsigned not null auto_increment, - `name` varchar(64) not null default '', - `email` varchar(64) not null default '', - `password` varchar(64) not null default '', - `created_at` datetime not null default '0000-00-00 00:00:00', - `updated_at` timestamp not null, - `email_confirmation_code` varchar(64) not null default '', - PRIMARY KEY `id` (`id`), - KEY `email_confirmation_code` (`email_confirmation_code`), - KEY `created_at` (`created_at`), - KEY `updated_at` (`updated_at`)) ENGINE=InnoDB CHARSET=utf8 COMMENT='Users'; - - -create table if not exists `users` ( - `id` int(11) unsigned not null auto_increment, - `name` varchar(64) not null default '', - `email` varchar(64) not null default '', - `password` varchar(64) not null default '', - `created_at` datetime not null default '0000-00-00 00:00:00', - `updated_at` timestamp not null, - `email_confirmation_code` varchar(64) not null default '', - PRIMARY KEY `id` (`id`), - KEY `email_confirmation_code` (`email_confirmation_code`), - KEY `created_at` (`created_at`), - KEY `updated_at` (`updated_at`)) ENGINE=InnoDB CHARSET=utf8 COMMENT='Users'; diff --git a/tests/DbQueryBuilderTest.php b/tests/DbQueryBuilderTest.php new file mode 100644 index 0000000..326aef0 --- /dev/null +++ b/tests/DbQueryBuilderTest.php @@ -0,0 +1,45 @@ +queryBuilder = new DbQueryBuilder(); + } + + public function testCreateInsertQuery() { + $params = array( + 'name' => 'Kirill', + 'date' => new DbExpression('NOW()'), + 'value' => 10, + ); + $this->queryBuilder = new DbQueryBuilder(); + $query = $this->queryBuilder->setSchema('test')->setTable('test')->insert($params); + $this->assertEquals('INSERT INTO `test`.`test` (`name`, `date`, `value`) VALUES (:name, NOW(), :value)', $query); + $this->assertEquals(array(':name' => 'Kirill', ':value' => '10'), $this->queryBuilder->getBindParams()); + } + + public function testUpdateQuery() { + $criteria = new DbCriteria(); + $criteria->conditions = array('id = :id'); + $query = $this->queryBuilder->update($update_fields, $criteria); + $this->markTestIncomplete(); + } + + public function testSelectQuery() { + $this->markTestIncomplete(); + } + + public function testJoinQuery() { + $this->markTestIncomplete(); + } + +} diff --git a/TestModel.php b/tests/ModelTest.php similarity index 67% rename from TestModel.php rename to tests/ModelTest.php index 3a45752..ac8b892 100644 --- a/TestModel.php +++ b/tests/ModelTest.php @@ -5,14 +5,16 @@ */ require_once 'PHPUnit/Autoload.php'; -require_once 'ModelClass.php'; +require_once '../ModelClass.php'; +require_once '../DbExpression.php'; +require_once '../DbDateTime.php'; /** * @backupGlobals disabled * @backupStaticAttributes disabled */ -class TestModel extends PHPUnit_Framework_TestCase { +class ModelTest extends PHPUnit_Framework_TestCase { public static function setUpBeforeClass() { global $dbh; @@ -65,14 +67,25 @@ public function testCreateModel() { $model= new ModelClass(); $model->string = 'lorem ipsum dolor'; $model->int = 10; - $model->date = 'NOW()'; - $model->timestamp = 'NOW()'; + $model->date = new DbExpression('NOW() + INTERVAL 10 HOUR'); + $model->timestamp = new DbExpression('NOW()'); $model->decimal = 10.03; $model->float = 10/3; - $this->assertTrue($model->save(), 'save fuckup'); + $save_response = $model->save(); + $this->assertTrue($save_response); $this->assertEquals(10, $model->int); - echo $model->date; - $this->assertEquals(10, $model->date); } + public function testCreateModel2() { + $model= new ModelClass(); + $model->string = "The name of the song was: \"Qui pense a l'amour, a l'amour\""; + $model->int = 100000; + $model->date = new DbDateTime('NOW - 100 YEAR + 2 HOUR'); + $model->timestamp = new DbExpression('NOW()'); + $model->decimal = 10.03; + $model->float = 10/3; + $save_response = $model->save(); + $this->assertTrue($save_response); + $this->assertEquals(100000, $model->int); + } } diff --git a/TestUser.php b/tests/UserTest.php similarity index 85% rename from TestUser.php rename to tests/UserTest.php index d148764..e9ebb94 100644 --- a/TestUser.php +++ b/tests/UserTest.php @@ -6,7 +6,7 @@ require_once 'PHPUnit/Autoload.php'; -class TestUserTest extends PHPUnit_Framework_TestCase { +class UserTest extends PHPUnit_Framework_TestCase { public function setUp() { } diff --git a/tests/config.xml b/tests/config.xml new file mode 100644 index 0000000..17ed4fd --- /dev/null +++ b/tests/config.xml @@ -0,0 +1 @@ + diff --git a/tests/data/schema.sql b/tests/data/schema.sql new file mode 100644 index 0000000..236a735 --- /dev/null +++ b/tests/data/schema.sql @@ -0,0 +1,37 @@ +-- +-- @author Kirill "Nemoden" K +-- schema for tests (MySQL) +-- + +create database if not exists `test` default character set = utf8 default collate = utf8_general_ci; + +use `test`; + +create table if not exists `people` ( + `id` int(11) unsigned not null auto_increment, + `name` varchar(255) not null default '', + `address` text, + `birthday` datetime not null default '0000-00-00 00:00:00', -- test dates < 1970 + `created_at` datetime not null default '0000-00-00 00:00:00', -- test dates + `updated_at` timstamp not null, + `age` tinyint(4) not null, -- test field setter + `gender` set('M', 'F') not null, -- test set + PRIMARY KEY `id` (`id`), + KEY `birthday` (`birthday`), + KEY `created_at` (`created_at`), + KEY `gender` (`gender`), + KEY `gender_age` (`gender`, `age`) +) ENGINE=InnoDB CHARSET=utf8 COMMENT='People table for test cases'; + +create table if not exists `users` ( + `id` int(11) unsigned not null auto_increment, + `name` varchar(64) not null default '', + `email` varchar(64) not null default '', + `password` varchar(64) not null default '', -- test field setter + `created_at` datetime not null default '0000-00-00 00:00:00', + `updated_at` timestamp not null, + `email_confirmation_code` varchar(64) not null default '', -- test field setter + PRIMARY KEY `id` (`id`), + KEY `email_confirmation_code` (`email_confirmation_code`), + KEY `created_at` (`created_at`), + KEY `updated_at` (`updated_at`)) ENGINE=InnoDB CHARSET=utf8 COMMENT='Users';