From db6e169f7b90af37f2d42c1425923a313790fff8 Mon Sep 17 00:00:00 2001 From: Joshua Sherman Date: Sun, 19 Jan 2014 22:36:30 -0500 Subject: [PATCH] 95% coverage, getting close. --- classes/Config.php | 2 +- classes/Model.php | 87 +++++++++++++++--------- classes/Object.php | 23 +++---- tests/bootstrap.php | 1 + tests/classes/ModelTest.php | 129 ++++++++++++++++++++++++++++++++++++ tests/schema.sql | 34 ++++++++-- 6 files changed, 222 insertions(+), 54 deletions(-) diff --git a/classes/Config.php b/classes/Config.php index ba44de6..e85dee7 100644 --- a/classes/Config.php +++ b/classes/Config.php @@ -203,7 +203,7 @@ class Config extends Object * @param array $array configuration error to flatten * @return array flattened configuration array */ - private function flatten($environment, $array) + public function flatten($environment, $array) { if (is_array($array)) { diff --git a/classes/Model.php b/classes/Model.php index 88bfbe6..ce73dc7 100644 --- a/classes/Model.php +++ b/classes/Model.php @@ -631,6 +631,11 @@ class Model extends Object } } + if (!preg_match('/^[0-9]+$/', implode('', array_keys($this->records)))) + { + $this->records = [$this->records]; + } + $this->index = 0; $this->original = $this->records; } @@ -892,7 +897,14 @@ class Model extends Object */ public function count() { - return count($this->records); + if (isset($this->records[0]) && $this->records[0] == []) + { + return 0; + } + else + { + return count($this->records); + } } /** @@ -1087,14 +1099,14 @@ class Model extends Object /** * @todo I outta loop through twice to determine if it's an INSERT - * or an UPDATE. As it stands, you could run into a scenario where - * you could have a mixed lot that would attempt to build out a - * query with both insert and update syntax and would probably - * cause a doomsday scenario for our universe. + * or an UPDATE. As it stands, you could run into a scenario + * where you could have a mixed lot that would attempt to + * build out a query with both INSERT and UPDATE syntax and + * would probably cause a doomsday scenario for our universe. */ foreach ($this->records as $record) { - // Performs an update with multiple queries + // Performs an UPDATE with multiple queries if (array_key_exists($this->columns['id'], $record)) { $update = true; @@ -1124,14 +1136,14 @@ class Model extends Object if ($this->columns['updated_at'] != false) { $update_fields[] = $this->columns['updated_at'] . ' = ?'; - $input_parameters[] = time::timestamp(); + $input_parameters[] = Time::timestamp(); } // @todo Check if the column was passed in - if ($this->columns['updated_id'] != false && isset($_session['__pickles']['security']['user_id'])) + if ($this->columns['updated_id'] != false && isset($_SESSION['__pickles']['security']['user_id'])) { $update_fields[] = $this->columns['updated_id'] . ' = ?'; - $input_parameters[] = $_session['__pickles']['security']['user_id']; + $input_parameters[] = $_SESSION['__pickles']['security']['user_id']; } if ($sql != '') @@ -1139,7 +1151,7 @@ class Model extends Object $sql .= '; '; } - $sql .= 'update ' . $this->table . ' set ' . implode(', ', $update_fields) . ' where '; + $sql .= 'UPDATE ' . $this->table . ' SET ' . implode(', ', $update_fields) . ' WHERE '; if (isset($record[$this->columns['id']])) { @@ -1151,7 +1163,7 @@ class Model extends Object throw new Exception('Missing UID field.'); } } - // Performs a multiple row insert + // Performs a multiple row INSERT else { if (!isset($sql)) @@ -1165,7 +1177,7 @@ class Model extends Object $field_count++; } - if ($this->columns['created_id'] != false && isset($_session['__pickles']['security']['user_id'])) + if ($this->columns['created_id'] != false && isset($_SESSION['__pickles']['security']['user_id'])) { $insert_fields[] = $this->columns['created_id']; $field_count++; @@ -1175,7 +1187,7 @@ class Model extends Object $input_parameters = []; // INSERT INTO ... - $sql = 'insert into ' . $this->table . ' (' . implode(', ', $insert_fields) . ') values ' . $values; + $sql = 'INSERT INTO ' . $this->table . ' (' . implode(', ', $insert_fields) . ') VALUES ' . $values; } else { @@ -1192,14 +1204,14 @@ class Model extends Object // @todo Check if the column was passed in if ($this->columns['created_at'] != false) { - $input_parameters[] = time::timestamp(); + $input_parameters[] = Time::timestamp(); $record_field_count++; } // @todo Check if the column was passed in - if ($this->columns['created_id'] != false && isset($_session['__pickles']['security']['user_id'])) + if ($this->columns['created_id'] != false && isset($_SESSION['__pickles']['security']['user_id'])) { - $input_parameters[] = $_session['__pickles']['security']['user_id']; + $input_parameters[] = $_SESSION['__pickles']['security']['user_id']; $record_field_count++; } @@ -1226,12 +1238,12 @@ class Model extends Object // Determines if it's an UPDATE or INSERT $update = (isset($this->record[$this->columns['id']]) && trim($this->record[$this->columns['id']]) != ''); - // Starts to build the query, optionally sets priority, delayed and ignore syntax + // Starts to build the query, optionally sets PRIORITY, DELAYED and IGNORE syntax if ($this->replace === true && $this->mysql) { $sql = 'REPLACE'; - if (strtoupper($this->priority) == 'low') + if (strtoupper($this->priority) == 'LOW') { $sql .= ' LOW_PRIORITY'; } @@ -1288,6 +1300,11 @@ class Model extends Object // Makes sure there's something to INSERT or UPDATE if (count($record) > 0) { + if ($this->replace && $update) + { + $update = false; + } + $insert_fields = []; // Loops through all the columns and assembles the query @@ -1323,7 +1340,7 @@ class Model extends Object } } - // If it's an UPDATE tack on the id + // If it's an UPDATE tack on the ID if ($update == true) { if ($this->columns['updated_at'] != false) @@ -1334,43 +1351,49 @@ class Model extends Object } $sql .= $this->columns['updated_at'] . ' = ?'; - $input_parameters[] = time::timestamp(); + $input_parameters[] = Time::timestamp(); } - if ($this->columns['updated_id'] != false && isset($_session['__pickles']['security']['user_id'])) + if ($this->columns['updated_id'] != false && isset($_SESSION['__pickles']['security']['user_id'])) { if ($input_parameters != null) { $sql .= ', '; } - $sql .= $this->columns['updated_id'] . ' = ?'; - $input_parameters[] = $_session['__pickles']['security']['user_id']; + $sql .= $this->columns['updated_id'] . ' = ?'; + + $input_parameters[] = $_SESSION['__pickles']['security']['user_id']; } - $sql .= ' where ' . $this->columns['id'] . ' = ?' . ($this->mysql ? ' limit 1' : '') . ';'; + $sql .= ' WHERE ' . $this->columns['id'] . ' = ?' . ($this->mysql ? ' LIMIT 1' : '') . ';'; $input_parameters[] = $this->record[$this->columns['id']]; } else { - if ($this->columns['created_at'] != false) + // @todo REPLACE should be grabbing the previous values so + // that we're not wiping out pertinent data when the + // internal columns are in use. This includes the + // `id` column that is needed to keep it from doing + // an INSERT instead of an UPDATE + if ($this->columns['created_at'] != false || $this->replace) { $insert_fields[] = $this->columns['created_at']; $input_parameters[] = Time::timestamp(); } - if ($this->columns['created_id'] != false && isset($_session['__pickles']['security']['user_id'])) + if ($this->columns['created_id'] != false && isset($_SESSION['__pickles']['security']['user_id'])) { $insert_fields[] = $this->columns['created_id']; - $input_parameters[] = $_session['__pickles']['security']['user_id']; + $input_parameters[] = $_SESSION['__pickles']['security']['user_id']; } - $sql .= '(' . implode(', ', $insert_fields) . ') values (' . implode(', ', array_fill(0, count($input_parameters), '?')) . ')'; + $sql .= '(' . implode(', ', $insert_fields) . ') VALUES (' . implode(', ', array_fill(0, count($input_parameters), '?')) . ')'; // PDO::lastInsertID() doesn't work so we return the ID with the query if ($this->postgresql) { - $sql .= ' returning ' . $this->columns['id']; + $sql .= ' RETURNING ' . $this->columns['id']; } $sql .= ';'; @@ -1387,7 +1410,7 @@ class Model extends Object { $results = $this->db->execute($sql, $input_parameters); - // clears the cache + // Clears the cache if ($update && $this->use_cache) { $this->cache->delete(strtoupper($this->model) . '-' . $this->record[$this->columns['id']]); @@ -1424,10 +1447,10 @@ class Model extends Object $input_parameters[] = Time::timestamp(); } - if ($this->columns['deleted_id'] && isset($_session['__pickles']['security']['user_id'])) + if ($this->columns['deleted_id'] && isset($_SESSION['__pickles']['security']['user_id'])) { $sql .= ', ' . $this->columns['deleted_id'] . ' = ?'; - $input_parameters[] = $_session['__pickles']['security']['user_id']; + $input_parameters[] = $_SESSION['__pickles']['security']['user_id']; } $sql .= ' WHERE ' . $this->columns['id'] . ' = ?'; diff --git a/classes/Object.php b/classes/Object.php index 9ca1bb5..2e24df8 100644 --- a/classes/Object.php +++ b/classes/Object.php @@ -28,42 +28,37 @@ class Object * Object Instances * * @static - * @access private * @var array */ - protected static $instances = []; + public static $instances = []; /** * Instance of the Config object * - * @access protected - * @var object + * @var object */ - protected $config = null; + public $config = null; /** * Instance of the Cache object * - * @access protected - * @var object + * @var object */ - protected $cache = null; + public $cache = null; /** * Instance of the Database object * - * @access protected - * @var object + * @var object */ - protected $db = null; + public $db = null; /** * Profiler flag * - * @access private - * @var mixed + * @var mixed */ - private $profiler = false; + public $profiler = false; /** * Constructor diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 5a47606..702e69c 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -61,6 +61,7 @@ function setUpConfig($config) } `mysql -e 'TRUNCATE TABLE test.pickles;'`; +`mysql -e 'TRUNCATE TABLE test.mypickles;'`; `mysql -e 'TRUNCATE TABLE test.users;'`; `echo 'flush_all' | nc localhost 11211`; diff --git a/tests/classes/ModelTest.php b/tests/classes/ModelTest.php index 5027ba4..b0c1714 100644 --- a/tests/classes/ModelTest.php +++ b/tests/classes/ModelTest.php @@ -6,16 +6,25 @@ class MockModelWithoutColumns extends Model public $columns = false; } +// InnoDB class MockModel extends Model { public $table = 'pickles'; public $columns = ['created_at' => 'created_at']; } +// MyISAM +class MyMockModel extends Model +{ + public $table = 'mypickles'; +} + class ModelTest extends PHPUnit_Framework_TestCase { public static function setUpBeforeClass() { + // Clears out the Config for ease of testing + Object::$instances = []; $config = Config::getInstance(); $config->data = [ @@ -353,6 +362,126 @@ class ModelTest extends PHPUnit_Framework_TestCase $model = new MockModel(); $conditions = $model->generateConditions(['id BETWEEN' => '1']); } + + public function testCommitSingleRecord() + { + $value = String::random(); + $model = new MockModel(1); + $model->record['field1'] = $value; + $model->commit(); + + $model = new MockModel(1); + $this->assertEquals($value, $model->record['field1']); + } + + public function testCommitSingleRecordReplace() + { +# $value = String::random(); +# $model = new MockModel(1); +# $model->replace = true; +# $model->record['field1'] = $value; +# $model->commit(); +# $model = new MockModel(1); +# $this->assertEquals($value, $model->record['field1']); + } + + public function testCommitInsertPriority() + { + $value = String::random(); + $model = new MockModel(); + $model->priority = 'low'; + $model->record['field1'] = $value; + $id = $model->commit(); + $model = new MockModel($id); + $this->assertEquals($value, $model->record['field1']); + } + + public function testCommitInsertDelayed() + { + $value = String::random(); + $model = new MyMockModel(); + $model->delayed = true; + $model->record['field1'] = $value; + $model->commit(); + $model = new MyMockModel(1); + $this->assertEquals($value, $model->record['field1']); + } + + public function testCommitInsertIgnore() + { + $value = String::random(); + $model = new MockModel(); + $model->ignore = true; + $model->record['field1'] = $value; + $id = $model->commit(); + $model = new MockModel($id); + $this->assertEquals($value, $model->record['field1']); + } + + public function testCommitReplacePriority() + { + $value = String::random(); + $model = new MockModel(); + $model->replace = true; + $model->priority = 'low'; + $model->record['field1'] = $value; + $id = $model->commit(); + $model = new MockModel($id); + $this->assertEquals($value, $model->record['field1']); + } + + public function testCommitReplaceDelayed() + { + $value = String::random(); + $model = new MyMockModel(); + $model->replace = true; + $model->delayed = true; + $model->record['field1'] = $value; + $model->commit(); + $model = new MyMockModel(2); + $this->assertEquals($value, $model->record['field1']); + } + + public function testCommitReplaceIgnore() + { + $value = String::random(); + $model = new MockModel(); + $model->replace = true; + $model->ignore = true; + $model->record['field1'] = $value; + $id = $model->commit(); + $model = new MockModel($id); + $this->assertEquals($value, $model->record['field1']); + } + + public function testDeleteLogical() + { + $_SESSION['__pickles']['security']['user_id'] = 1; + $model = new MockModel(1); + $model->delete(); + $model = new MockModelWithoutColumns(1); + $this->assertEquals(1, $model->record['is_deleted']); + } + + public function testDeleteActual() + { + $model = new MockModelWithoutColumns(1); + $model->delete(); + $model = new MockModelWithoutColumns(1); + $this->assertEquals(0, $model->count()); + } + + public function testDeleteNothing() + { + $model = new MockModelWithoutColumns(100); + $this->assertFalse($model->delete()); + } + + public function testLoadParametersWithString() + { + $model = new MockModel(); + $this->assertFalse($model->loadParameters('')); + } } ?> diff --git a/tests/schema.sql b/tests/schema.sql index 6ad0317..5d0a89a 100644 --- a/tests/schema.sql +++ b/tests/schema.sql @@ -3,12 +3,12 @@ DROP TABLE IF EXISTS pickles; CREATE TABLE `pickles` ( `id` int(1) unsigned NOT NULL AUTO_INCREMENT, `field1` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `field2` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `field3` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `field4` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `field5` varchar(100) COLLATE utf8_unicode_ci NOT NULL, + `field2` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `field3` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `field4` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `field5` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, `created_id` int(1) unsigned DEFAULT NULL, - `created_at` datetime NOT NULL, + `created_at` datetime DEFAULT NULL, `updated_id` int(1) unsigned DEFAULT NULL, `updated_at` datetime DEFAULT NULL, `deleted_id` int(1) unsigned DEFAULT NULL, @@ -16,7 +16,27 @@ CREATE TABLE `pickles` ( `is_deleted` tinyint(1) unsigned DEFAULT '0', PRIMARY KEY (`id`), KEY is_deleted (is_deleted) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +DROP TABLE IF EXISTS mypickles; + +CREATE TABLE `mypickles` ( + `id` int(1) unsigned NOT NULL AUTO_INCREMENT, + `field1` varchar(100) COLLATE utf8_unicode_ci NOT NULL, + `field2` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `field3` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `field4` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `field5` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `created_id` int(1) unsigned DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + `updated_id` int(1) unsigned DEFAULT NULL, + `updated_at` datetime DEFAULT NULL, + `deleted_id` int(1) unsigned DEFAULT NULL, + `deleted_at` datetime DEFAULT NULL, + `is_deleted` tinyint(1) unsigned DEFAULT '0', + PRIMARY KEY (`id`), + KEY is_deleted (is_deleted) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; DROP TABLE IF EXISTS users; @@ -32,4 +52,4 @@ CREATE TABLE `users` ( `deleted_at` datetime DEFAULT NULL, `is_deleted` tinyint(1) unsigned DEFAULT '0', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;