From e8c7537514d1432cd154ac35363d97c2d33cdde4 Mon Sep 17 00:00:00 2001 From: Petter Blomberg Date: Mon, 7 May 2012 14:29:01 +0200 Subject: [PATCH 01/75] Adding exception for bad column names like "@order:desc" --- BasicObject.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/BasicObject.php b/BasicObject.php index 347b24f..597cf2c 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -579,6 +579,9 @@ private static function handle_params($params, &$joins, &$wheres, &$order, &$tab } if($column[0] == '@'){ $column = explode(':', $column); + if(count($column)>1) { + throw new Exception("Invalid column"); + } $column = $column[0]; // special parameter switch($column){ From 7a18add0c16785c5b33a9dd6c1f4d93ca3de790b Mon Sep 17 00:00:00 2001 From: Petter Blomberg Date: Tue, 12 Jun 2012 18:09:54 +0200 Subject: [PATCH 02/75] @order should accept both :DESC and :desc --- BasicObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BasicObject.php b/BasicObject.php index 597cf2c..543087d 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -594,7 +594,7 @@ private static function handle_params($params, &$joins, &$wheres, &$order, &$tab } foreach($value as $o){ $desc = false; - if(substr($o,-5) == ':desc'){ + if(strtolower(substr($o,-5)) == ':desc'){ $desc = true; $o = substr($o, 0,-5); } From aa5d65b61f49487f443ff16026a007970c4da8fd Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Wed, 13 Feb 2013 14:21:29 +0100 Subject: [PATCH 03/75] Add memcache of primary_keys --- BasicObject.php | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 35454ea..5d298d0 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -9,6 +9,13 @@ abstract class BasicObject { protected $_old_key = array(); protected $_exists; + /* + * Memcache for caching database structure between requests + */ + private static $memcache = null; + + private static $column_ids = array(); + public static $output_htmlspecialchars; /** @@ -46,8 +53,6 @@ private static function id_name($class_name = null){ private static function primary_key($class_name = null) { global $db; - static $column_ids = array(); - if(class_exists($class_name) && is_subclass_of($class_name, 'BasicObject')){ $table_name = $class_name::table_name(); } elseif($class_name == null) { @@ -55,7 +60,7 @@ private static function primary_key($class_name = null) { } else { $table_name = $class_name; } - if(!array_key_exists($table_name, $column_ids)){ + if(!array_key_exists($table_name, BasicObject::$column_ids)){ $stmt = $db->prepare(" SELECT `COLUMN_NAME` @@ -73,14 +78,45 @@ private static function primary_key($class_name = null) { $stmt->store_result(); $stmt->bind_result($index); - $column_ids[$table_name] = array(); + BasicObject::$column_ids[$table_name] = array(); while($stmt->fetch()) { - $column_ids[$table_name][] = $index; + BasicObject::$column_ids[$table_name][] = $index; } + static::update_structure_cache(); $stmt->close(); } - return $column_ids[$table_name]; + return BasicObject::$column_ids[$table_name]; + } + + public static function enable_structure_cache($memcache_host, $memcache_port = null) { + if($memcache_port == null) $memcache_port = ini_get("memcache.default_port"); + BasicObject::$memcache = new Memcache(); + if(BasicObject::$memcache->connect($memcache_host, $memcache_port)) { + $stored = BasicObject::$memcache->get("column_ids"); + if($stored) { + BasicObject::$column_ids = unserialize($stored); + } + } else { + trigger_error("Failed to connect to memcache server", E_USER_WARNING); + BasicObject::$memcache = null; + } + } + + public static function clear_structure_cache($memcache_host, $memcache_port = null) { + if($memcache_port == null) $memcache_port = ini_get("memcache.default_port"); + $memcache = new Memcache(); + if($memcache->connect($memcache_host, $memcache_port)) { + $memcache->flush(); + } else { + trigger_error("Failed to connect to memcache server", E_USER_WARNING); + } + } + + private static function update_structure_cache() { + if(BasicObject::$memcache) { + BasicObject::$memcache->set("column_ids", serialize(BasicObject::$column_ids)); + } } private static function unique_identifier($class_name = null) { From 4fa612223f7485dff22fa88b5eb696223bc2a73e Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Wed, 13 Feb 2013 15:12:06 +0100 Subject: [PATCH 04/75] Cache connection table too --- BasicObject.php | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 5d298d0..ab516a6 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -15,6 +15,7 @@ abstract class BasicObject { private static $memcache = null; private static $column_ids = array(); + private static $connection_table = array(); public static $output_htmlspecialchars; @@ -82,7 +83,7 @@ private static function primary_key($class_name = null) { while($stmt->fetch()) { BasicObject::$column_ids[$table_name][] = $index; } - static::update_structure_cache(); + static::store_column_ids(); $stmt->close(); } @@ -97,6 +98,10 @@ public static function enable_structure_cache($memcache_host, $memcache_port = n if($stored) { BasicObject::$column_ids = unserialize($stored); } + $stored = BasicObject::$memcache->get("connection_table"); + if($stored) { + BasicObject::$connection_table = unserialize($stored); + } } else { trigger_error("Failed to connect to memcache server", E_USER_WARNING); BasicObject::$memcache = null; @@ -113,12 +118,18 @@ public static function clear_structure_cache($memcache_host, $memcache_port = nu } } - private static function update_structure_cache() { + private static function store_column_ids() { if(BasicObject::$memcache) { BasicObject::$memcache->set("column_ids", serialize(BasicObject::$column_ids)); } } + private static function store_connection_table() { + if(BasicObject::$memcache) { + BasicObject::$memcache->set("connection_table", serialize(BasicObject::$connection_table)); + } + } + private static function unique_identifier($class_name = null) { if(class_exists($class_name) && is_subclass_of($class_name, 'BasicObject')){ $table_name = $class_name::table_name(); @@ -1006,14 +1017,13 @@ public static function one($params = array()) { private static function connection($table1, $table2) { global $db; - static $data; if(strcmp($table1, $table2) < 0){ $tmp = $table1; $table1 = $table2; $table2 = $tmp; } - if(!isset($data[$table1]) || !isset($data[$table1][$table2])){ - $data[$table1][$table2] = array(); + if(!isset(BasicObject::$connection_table[$table1]) || !isset(BasicObject::$connection_table[$table1][$table2])){ + BasicObject::$connection_table[$table1][$table2] = array(); $stmt = $db->prepare(" SELECT `key_column_usage`.`TABLE_NAME`, @@ -1041,19 +1051,21 @@ private static function connection($table1, $table2) { $stmt->execute(); $stmt->store_result(); $stmt->bind_result( - $data[$table1][$table2]['TABLE_NAME'], - $data[$table1][$table2]['COLUMN_NAME'], - $data[$table1][$table2]['REFERENCED_TABLE_NAME'], - $data[$table1][$table2]['REFERENCED_COLUMN_NAME'] + BasicObject::$connection_table[$table1][$table2]['TABLE_NAME'], + BasicObject::$connection_table[$table1][$table2]['COLUMN_NAME'], + BasicObject::$connection_table[$table1][$table2]['REFERENCED_TABLE_NAME'], + BasicObject::$connection_table[$table1][$table2]['REFERENCED_COLUMN_NAME'] ); if(!$stmt->fetch()){ - $data[$table1][$table2] = false; + BasicObject::$connection_table[$table1][$table2] = false; } else if($stmt->num_rows > 1) { throw new Exception("Ambigious database, can't tell which relation between $table1 and $table2 to use. Remove one relation or override __get."); } $stmt->close(); + + BasicObject::store_connection_table(); } - return $data[$table1][$table2]; + return BasicObject::$connection_table[$table1][$table2]; } private static function get_database_name() { From de905a811a7fe2f270132d58b909efd73a649cc9 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Wed, 13 Feb 2013 16:03:35 +0100 Subject: [PATCH 05/75] Take a memcache instance instead of conn info --- BasicObject.php | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index ab516a6..8a74b7f 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -90,43 +90,35 @@ private static function primary_key($class_name = null) { return BasicObject::$column_ids[$table_name]; } - public static function enable_structure_cache($memcache_host, $memcache_port = null) { - if($memcache_port == null) $memcache_port = ini_get("memcache.default_port"); - BasicObject::$memcache = new Memcache(); - if(BasicObject::$memcache->connect($memcache_host, $memcache_port)) { - $stored = BasicObject::$memcache->get("column_ids"); - if($stored) { - BasicObject::$column_ids = unserialize($stored); - } - $stored = BasicObject::$memcache->get("connection_table"); - if($stored) { - BasicObject::$connection_table = unserialize($stored); - } - } else { - trigger_error("Failed to connect to memcache server", E_USER_WARNING); - BasicObject::$memcache = null; + /** + * Enables structure cache using the provided Memcache object + * The memcache instance must be connected + */ + public static function enable_structure_cache($memcache) { + BasicObject::$memcache = $memcache; + $stored = BasicObject::$memcache->get("column_ids"); + if($stored) { + BasicObject::$column_ids = unserialize($stored); + } + $stored = BasicObject::$memcache->get("connection_table"); + if($stored) { + BasicObject::$connection_table = unserialize($stored); } } - public static function clear_structure_cache($memcache_host, $memcache_port = null) { - if($memcache_port == null) $memcache_port = ini_get("memcache.default_port"); - $memcache = new Memcache(); - if($memcache->connect($memcache_host, $memcache_port)) { - $memcache->flush(); - } else { - trigger_error("Failed to connect to memcache server", E_USER_WARNING); - } + public static function clear_structure_cache($memcache) { + $memcache->flush(); } private static function store_column_ids() { if(BasicObject::$memcache) { - BasicObject::$memcache->set("column_ids", serialize(BasicObject::$column_ids)); + BasicObject::$memcache->set("column_ids", serialize(BasicObject::$column_ids), 0, 0); /* no expire */ } } private static function store_connection_table() { if(BasicObject::$memcache) { - BasicObject::$memcache->set("connection_table", serialize(BasicObject::$connection_table)); + BasicObject::$memcache->set("connection_table", serialize(BasicObject::$connection_table), 0, 0); /* No expire */ } } From d2250d314d4d3dc233324c26126003216a6d31e5 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Wed, 13 Feb 2013 16:13:23 +0100 Subject: [PATCH 06/75] Cache columns too --- BasicObject.php | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 8a74b7f..965cff6 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -16,6 +16,7 @@ abstract class BasicObject { private static $column_ids = array(); private static $connection_table = array(); + private static $tables = array(); public static $output_htmlspecialchars; @@ -104,6 +105,10 @@ public static function enable_structure_cache($memcache) { if($stored) { BasicObject::$connection_table = unserialize($stored); } + $stored = BasicObject::$memcache->get("tables"); + if($stored) { + BasicObject::$tables = unserialize($stored); + } } public static function clear_structure_cache($memcache) { @@ -122,6 +127,12 @@ private static function store_connection_table() { } } + private static function store_tables() { + if(BasicObject::$memcache) { + BasicObject::$memcache->set("tables", serialize(BasicObject::$tables), 0, 0); /* No expire */ + } + } + private static function unique_identifier($class_name = null) { if(class_exists($class_name) && is_subclass_of($class_name, 'BasicObject')){ $table_name = $class_name::table_name(); @@ -973,11 +984,11 @@ private static function fix_join($path, &$joins, $parent_columns, $parent){ } private static function in_table($column, $table){ - static $tables = array(); - if(!isset($tables[$table])){ - $tables[$table] = self::columns($table); + if(!isset(BasicObject::$tables[$table])){ + BasicObject::$tables[$table] = self::columns($table); + BasicObject::store_tables(); } - return in_array($column, $tables[$table]); + return in_array($column, BasicObject::$tables[$table]); } /** From e933a7edfa5a351a62cf57c40fd87c26d7c3fa28 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Wed, 13 Feb 2013 16:36:02 +0100 Subject: [PATCH 07/75] Cache column names too --- BasicObject.php | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 965cff6..658c14a 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -17,6 +17,7 @@ abstract class BasicObject { private static $column_ids = array(); private static $connection_table = array(); private static $tables = array(); + private static $columns = array(); public static $output_htmlspecialchars; @@ -97,18 +98,18 @@ private static function primary_key($class_name = null) { */ public static function enable_structure_cache($memcache) { BasicObject::$memcache = $memcache; + $stored = BasicObject::$memcache->get("column_ids"); - if($stored) { - BasicObject::$column_ids = unserialize($stored); - } + if($stored) BasicObject::$column_ids = unserialize($stored); + $stored = BasicObject::$memcache->get("connection_table"); - if($stored) { - BasicObject::$connection_table = unserialize($stored); - } + if($stored) BasicObject::$connection_table = unserialize($stored); + $stored = BasicObject::$memcache->get("tables"); - if($stored) { - BasicObject::$tables = unserialize($stored); - } + if($stored) BasicObject::$tables = unserialize($stored); + + $stored = BasicObject::$memcache->get("columns"); + if($stored) BasicObject::$columns = unserialize($stored); } public static function clear_structure_cache($memcache) { @@ -133,6 +134,12 @@ private static function store_tables() { } } + private static function store_columns() { + if(BasicObject::$memcache) { + BasicObject::$memcache->set("columns", serialize(BasicObject::$columns), 0, 0); /* No expire */ + } + } + private static function unique_identifier($class_name = null) { if(class_exists($class_name) && is_subclass_of($class_name, 'BasicObject')){ $table_name = $class_name::table_name(); @@ -874,8 +881,7 @@ public static function update_attributes($array, $options=array()) { private static function columns($table){ global $db; - static $columns = array(); - if(!isset($columns[$table])){ + if(!isset(BasicObject::$columns[$table])){ if(!self::is_table($table)){ throw new Exception("No such table '$table'"); } @@ -893,11 +899,12 @@ private static function columns($table){ $stmt->store_result(); $stmt->bind_result($column); while($stmt->fetch()){ - $columns[$table][] = $column; + BasicObject::$columns[$table][] = $column; } $stmt->close(); + BasicObject::store_columns(); } - return $columns[$table]; + return BasicObject::$columns[$table]; } private static function operator($expr){ From de7d85e2fed74976b1ba6a89071a4dc704c78d8f Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Wed, 13 Feb 2013 16:44:07 +0100 Subject: [PATCH 08/75] Cache from_field per requests --- BasicObject.php | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/BasicObject.php b/BasicObject.php index 658c14a..a63a352 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -9,6 +9,17 @@ abstract class BasicObject { protected $_old_key = array(); protected $_exists; + /* + * [ + * 'field' => [ + * value => object + * ] + * ] + */ + protected static $_from_field_cache = array(); + + protected static $_enable_cache = false; + /* * Memcache for caching database structure between requests */ @@ -21,6 +32,18 @@ abstract class BasicObject { public static $output_htmlspecialchars; + /* + * Methods for toggling query caching on and off + * Default: Off + */ + public static function disable_cache() { + BasicObject::$_enable_cache = false; + } + + public static function enable_cache() { + BasicObject::$_enable_cache = true; + } + /** * Runs the callback with a output_htmlspecialchars temporary value set * and returns the value that the callback returned @@ -396,6 +419,9 @@ public function commit() { $object = self::get_fresh_instance(); } $this->_data = $object->_data; + } else if(BasicObject::$_enable_cache) { + //Updated existing object, clear cache + self::$_from_field_cache = array(); } } @@ -451,6 +477,13 @@ public static function from_id($id){ protected static function from_field($field, $value, $type='s'){ global $db; + + if(BasicObject::$_enable_cache && isset(self::$_from_field_cache[$field][$value])) { + return self::$_from_field_cache[$field][$value]; + } + + $field_name = $field; + $table_name = static::table_name(); if(!self::in_table($field, $table_name)){ throw new Exception("No such column '$field' in table '$table_name'"); @@ -474,6 +507,13 @@ protected static function from_field($field, $value, $type='s'){ $object = new static($bind_results, true); } $stmt->close(); + + if(BasicObject::$_enable_cache) { + if(!isset(self::$_from_field_cache[$field_name])) self::$_from_field_cache[$field_name] = array(); + + self::$_from_field_cache[$field_name][$value] = $object; + } + return $object; } From f0b4fb75edb0c08bf9604d69f176f3928c07d699 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Wed, 13 Feb 2013 16:45:21 +0100 Subject: [PATCH 09/75] Fix spelling error in comment --- BasicObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BasicObject.php b/BasicObject.php index a63a352..5dd3f25 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -565,7 +565,7 @@ public static function sum($field, $params = array()) { /** * Returns the number of items matching the conditions. - * @param $params Array Se selection for structure of $params. + * @param $params Array See selection for structure of $params. * @returns Int the number of items matching the conditions. */ public static function count($params = array(), $debug = false){ From 1a3ab16195d02526f379139399cba9b4e29c7367 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Wed, 13 Feb 2013 17:19:06 +0100 Subject: [PATCH 10/75] Query caching --- BasicObject.php | 54 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/BasicObject.php b/BasicObject.php index 5dd3f25..e262da1 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -20,6 +20,13 @@ abstract class BasicObject { protected static $_enable_cache = false; + /* + * [ 'query' => result ] + */ + protected static $_selection_cache = array(); + protected static $_count_cache = array(); + protected static $_sum_cache = array(); + /* * Memcache for caching database structure between requests */ @@ -422,6 +429,9 @@ public function commit() { } else if(BasicObject::$_enable_cache) { //Updated existing object, clear cache self::$_from_field_cache = array(); + self::$_selection_cache = array(); + self::$_sum_cache = array(); + self::$_count_cache = array(); } } @@ -520,6 +530,15 @@ protected static function from_field($field, $value, $type='s'){ public static function sum($field, $params = array()) { global $db; $data = static::build_query($params, '*'); + + $cache_string = null; + if(BasicObject::$_enable_cache) { + $cache_string = implode(";", $data); + if(isset(self::$_sum_cache[$cache_string])) { + return self::$_sum_cache[$cache_string]; + } + } + $query = array_shift($data); $allowed_symbols=array('*', '+', '/', '-', ); if(is_array($field)) { @@ -560,6 +579,11 @@ public static function sum($field, $params = array()) { $stmt->bind_result($result); $stmt->fetch(); $stmt->close(); + + if(BasicObject::$_enable_cache) { + self::$_sum_cache[$cache_string] = $result; + } + return $result; } @@ -571,6 +595,15 @@ public static function sum($field, $params = array()) { public static function count($params = array(), $debug = false){ global $db; $data = static::build_query($params, 'count'); + + $cache_string = null; + if(BasicObject::$_enable_cache) { + $cache_string = implode(";", $data); + if(isset(self::$_count_cache[$cache_string])) { + return self::$_count_cache[$cache_string]; + } + } + $query = array_shift($data); if($debug) { echo "
$query
\n"; @@ -588,6 +621,11 @@ public static function count($params = array(), $debug = false){ $stmt->bind_result($result); $stmt->fetch(); $stmt->close(); + + if(BasicObject::$_enable_cache) { + self::$_count_cache[$cache_string] = $result; + } + return $result; } @@ -616,10 +654,19 @@ public static function count($params = array(), $debug = false){ public static function selection($params = array(), $debug=false){ global $db; $data = self::build_query($params, '*'); + + $cache_string = null; + if(BasicObject::$_enable_cache) { + $cache_string = implode(";", $data); + if(isset(self::$_selection_cache[$cache_string])) { + return self::$_selection_cache[$cache_string]; + } + } + $query = array_shift($data); $stmt = $db->prepare($query); if(!$stmt) { - throw new Exception("BasicObject: error parcing query: $query\n $db->error"); + throw new Exception("BasicObject: error parsing query: $query\n $db->error"); } foreach($data as $key => $value) { $data[$key] = &$data[$key]; @@ -656,6 +703,11 @@ public static function selection($params = array(), $debug=false){ $ret[] = new static($tmp, true); } $stmt->close(); + + if(BasicObject::$_enable_cache) { + self::$_selection_cache[$cache_string] = $ret; + } + return $ret; } From cac59131a6da05d9c5d2eeb89912c2d997f8745e Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Fri, 15 Feb 2013 14:42:39 +0100 Subject: [PATCH 11/75] Empty cache on create too --- BasicObject.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index e262da1..c2fb7eb 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -426,8 +426,10 @@ public function commit() { $object = self::get_fresh_instance(); } $this->_data = $object->_data; - } else if(BasicObject::$_enable_cache) { - //Updated existing object, clear cache + } + + //Clear cache + if(BasicObject::$_enable_cache) { self::$_from_field_cache = array(); self::$_selection_cache = array(); self::$_sum_cache = array(); From ec67e4956cbdf41f0632007d651bf67cb4da0af9 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Fri, 15 Feb 2013 18:13:50 +0100 Subject: [PATCH 12/75] Fix cache bug --- BasicObject.php | 56 +++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index c2fb7eb..885c7ec 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -9,6 +9,8 @@ abstract class BasicObject { protected $_old_key = array(); protected $_exists; + protected static $_global_cache_revision = 0; + protected static $_local_cache_revision = 0; /* * [ * 'field' => [ @@ -51,6 +53,10 @@ public static function enable_cache() { BasicObject::$_enable_cache = true; } + public static function invalidate_cache() { + ++BasicObject::$_global_cache_revision; + } + /** * Runs the callback with a output_htmlspecialchars temporary value set * and returns the value that the callback returned @@ -428,13 +434,7 @@ public function commit() { $this->_data = $object->_data; } - //Clear cache - if(BasicObject::$_enable_cache) { - self::$_from_field_cache = array(); - self::$_selection_cache = array(); - self::$_sum_cache = array(); - self::$_count_cache = array(); - } + BasicObject::invalidate_cache(); } /** @@ -490,8 +490,10 @@ public static function from_id($id){ protected static function from_field($field, $value, $type='s'){ global $db; - if(BasicObject::$_enable_cache && isset(self::$_from_field_cache[$field][$value])) { - return self::$_from_field_cache[$field][$value]; + static::validate_cache(); + + if(BasicObject::$_enable_cache && isset(static::$_from_field_cache[$field][$value])) { + return static::$_from_field_cache[$field][$value]; } $field_name = $field; @@ -521,9 +523,9 @@ protected static function from_field($field, $value, $type='s'){ $stmt->close(); if(BasicObject::$_enable_cache) { - if(!isset(self::$_from_field_cache[$field_name])) self::$_from_field_cache[$field_name] = array(); + if(!isset(static::$_from_field_cache[$field_name])) static::$_from_field_cache[$field_name] = array(); - self::$_from_field_cache[$field_name][$value] = $object; + static::$_from_field_cache[$field_name][$value] = $object; } return $object; @@ -533,11 +535,13 @@ public static function sum($field, $params = array()) { global $db; $data = static::build_query($params, '*'); + static::validate_cache(); + $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); - if(isset(self::$_sum_cache[$cache_string])) { - return self::$_sum_cache[$cache_string]; + if(isset(static::$_sum_cache[$cache_string])) { + return static::$_sum_cache[$cache_string]; } } @@ -583,7 +587,7 @@ public static function sum($field, $params = array()) { $stmt->close(); if(BasicObject::$_enable_cache) { - self::$_sum_cache[$cache_string] = $result; + static::$_sum_cache[$cache_string] = $result; } return $result; @@ -601,8 +605,8 @@ public static function count($params = array(), $debug = false){ $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); - if(isset(self::$_count_cache[$cache_string])) { - return self::$_count_cache[$cache_string]; + if(isset(static::$_count_cache[$cache_string])) { + return static::$_count_cache[$cache_string]; } } @@ -625,7 +629,7 @@ public static function count($params = array(), $debug = false){ $stmt->close(); if(BasicObject::$_enable_cache) { - self::$_count_cache[$cache_string] = $result; + static::$_count_cache[$cache_string] = $result; } return $result; @@ -657,11 +661,13 @@ public static function selection($params = array(), $debug=false){ global $db; $data = self::build_query($params, '*'); + static::validate_cache(); + $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); - if(isset(self::$_selection_cache[$cache_string])) { - return self::$_selection_cache[$cache_string]; + if(isset(static::$_selection_cache[$cache_string])) { + return static::$_selection_cache[$cache_string]; } } @@ -707,7 +713,7 @@ public static function selection($params = array(), $debug=false){ $stmt->close(); if(BasicObject::$_enable_cache) { - self::$_selection_cache[$cache_string] = $ret; + static::$_selection_cache[$cache_string] = $ret; } return $ret; @@ -1194,6 +1200,16 @@ public function __toString() { } return get_class($this). "{".implode(", ",$content)."}"; } + + protected static function validate_cache() { + if(BasicObject::$_enable_cache && BasicObject::$_global_cache_revision > static::$_local_cache_revision) { + static::$_from_field_cache = array(); + static::$_selection_cache = array(); + static::$_sum_cache = array(); + static::$_count_cache = array(); + static::$_local_cache_revision = BasicObject::$_global_cache_revision; + } + } } class UndefinedMemberException extends Exception{} class UndefinedFunctionException extends Exception{} From 930cac90015edd4eb74dc01391e099a30f9f0977 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Fri, 15 Feb 2013 19:00:09 +0100 Subject: [PATCH 13/75] Cache available tables --- BasicObject.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 885c7ec..9e9a707 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -36,7 +36,7 @@ abstract class BasicObject { private static $column_ids = array(); private static $connection_table = array(); - private static $tables = array(); + private static $tables = null; private static $columns = array(); public static $output_htmlspecialchars; @@ -1028,8 +1028,9 @@ private static function operator($expr){ private static function is_table($table){ global $db; - static $tables; - if(!isset($tables)){ + if(!isset(BasicObject::$tables)){ + BasicObject::$tables = array(); + $db_name = static::get_database_name(); $stmt = $db->prepare(" SELECT `table_name` @@ -1041,11 +1042,12 @@ private static function is_table($table){ $stmt->store_result(); $stmt->bind_result($table_); while($stmt->fetch()){ - $tables[] = strtolower($table_); + BasicObject::$tables[] = strtolower($table_); } $stmt->close(); + BasicObject::store_tables(); } - return in_array(strtolower($table), $tables); + return in_array(strtolower($table), BasicObject::$tables); } private static function fix_join($path, &$joins, $parent_columns, $parent){ @@ -1091,11 +1093,7 @@ private static function fix_join($path, &$joins, $parent_columns, $parent){ } private static function in_table($column, $table){ - if(!isset(BasicObject::$tables[$table])){ - BasicObject::$tables[$table] = self::columns($table); - BasicObject::store_tables(); - } - return in_array($column, BasicObject::$tables[$table]); + return in_array($column, self::columns($table)); } /** From e005da109ab29abd5a0de90d539c60f094796afb Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Fri, 15 Feb 2013 21:40:49 +0100 Subject: [PATCH 14/75] Add support for custom joins --- BasicObject.php | 93 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 9e9a707..bb48839 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -654,7 +654,16 @@ public static function count($params = array(), $debug = false){ * '@and' => array([]), * '@order' => array(<> [, <> ...]) | <>, * '@limit' => array(<> [, <>]), + * '@join[:<>]' => array( + * '<>[:<>]' => <> , + * ... + * ) * ) + * + * Joins: <>: The join type (eg. LEFT,RIGHT OUTER etc) + * This produces the join " <> JOIN <
> <> <> + * Operator can be 'on' or 'using' + * * @returns Array An array of Objects. */ public static function selection($params = array(), $debug=false){ @@ -749,7 +758,9 @@ private static function build_query($params, $select){ "FROM\n". " `".$table_name."`"; foreach($joins as $table => $join){ - $query .= " JOIN\n"; + $type = isset($join['type']) ? $join['type'] : ""; + $query .= " $type JOIN\n"; + if(isset($join['using'])){ $query .= " `".$table."` USING (`".$join['using']."`)"; } else { @@ -787,8 +798,8 @@ private static function handle_params($params, &$joins, &$wheres, &$order, &$tab $value = $value['value']; } if($column[0] == '@'){ - $column = explode(':', $column); - $column = $column[0]; + $column_split = explode(':', $column); + $column = $column_split[0]; // special parameter switch($column){ case '@custom_order': @@ -854,6 +865,40 @@ private static function handle_params($params, &$joins, &$wheres, &$order, &$tab $types .= self::handle_params($value, $joins, $where, $order, $table_name, $limit, $user_params, 'AND'); $wheres .= "(\n".substr($where, 0, -5)."\n) $glue\n"; break; + case '@join': + + if(count($column_split) > 1) { + $join_type = $column_split[1]; + } else { + $join_type = null; + } + + if(!is_array($value)) { + throw new Exception("Join must be array"); + } + foreach($value as $table => $condition) { + $table = explode(':', $table); + if(count($table) > 1) { + $operator = strtolower($table[1]); + if(! ($operator == "on" || $operator == "using") ) { + throw new Exception("Join operator must be 'on' or 'using'"); + } + } else { + $operator = "on"; + } + $table = $table[0]; + + $join = array( + $operator => $condition, + 'to' => static::table_name() + ); + if($join_type != null) { + $join['type'] = $join_type; + } + + $joins[$table] = $join; + } + break; default: throw new Exception("No such operator '".substr($column,1)."' (value '$value')"); } @@ -1052,35 +1097,41 @@ private static function is_table($table){ private static function fix_join($path, &$joins, $parent_columns, $parent){ $first = array_shift($path); + if(class_exists($first) && is_subclass_of($first, 'BasicObject')){ $first = $first::table_name(); } - + if(!self::is_table($first)){ throw new Exception("No such table '$first'"); } - $connection = self::connection($first, $parent); + $columns = self::columns($first); - if($connection){ - $joins[$first] = array( - 'to' => $parent, - 'on' => "`{$connection['TABLE_NAME']}`.`{$connection['COLUMN_NAME']}` = `{$connection['REFERENCED_TABLE_NAME']}`.`{$connection['REFERENCED_COLUMN_NAME']}`" - ); - } else { - $parent_id = self::id_name($parent); - $first_id = self::id_name($first); - if(in_array($first_id, $parent_columns)){ - $joins[$first] = array( - "to" => $parent, - "on" => "`$parent`.`$first_id` = `$first`.`$first_id`"); - } elseif(in_array($parent_id, $columns)) { + + if(!isset($joins[$first])) { + $connection = self::connection($first, $parent); + if($connection){ $joins[$first] = array( - "to" => $parent, - "on" => "`$parent`.`$parent_id` = `$first`.`$parent_id`"); + 'to' => $parent, + 'on' => "`{$connection['TABLE_NAME']}`.`{$connection['COLUMN_NAME']}` = `{$connection['REFERENCED_TABLE_NAME']}`.`{$connection['REFERENCED_COLUMN_NAME']}`" + ); } else { - throw new Exception("No connection from '$parent' to table '$first'"); + $parent_id = self::id_name($parent); + $first_id = self::id_name($first); + if(in_array($first_id, $parent_columns)){ + $joins[$first] = array( + "to" => $parent, + "on" => "`$parent`.`$first_id` = `$first`.`$first_id`"); + } elseif(in_array($parent_id, $columns)) { + $joins[$first] = array( + "to" => $parent, + "on" => "`$parent`.`$parent_id` = `$first`.`$parent_id`"); + } else { + throw new Exception("No connection from '$parent' to table '$first'"); + } } } + if(count($path) == 1) { $key = array_shift($path); if(!in_array($key, $columns)){ From 43e79d52a3ddb9ee5b1f9fe0f51442a188f3724a Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Fri, 15 Feb 2013 22:22:53 +0100 Subject: [PATCH 15/75] cosmetic: remove trailing whitespace --- ValidatingBasicObject.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/ValidatingBasicObject.php b/ValidatingBasicObject.php index ae152ea..50e0a5e 100644 --- a/ValidatingBasicObject.php +++ b/ValidatingBasicObject.php @@ -2,11 +2,11 @@ /** * This is a variant of basic object that has validations. * - * Validations are added to the model by implementing + * Validations are added to the model by implementing * protected function validation_hooks() (void) - * + * * In this function you can either use predefined validations by calling - * $this->predefined_validation_name('column_name') (see below) + * $this->predefined_validation_name('column_name') (see below) * or by creating your own validations. * * To indicate an error call $this->add_error($variable_name,$error_msg) @@ -35,11 +35,11 @@ * * validate_lenght_of($var) * - * Validates the lenght of $var + * Validates the lenght of $var * If no options are set no check is made * If more than one options are set, multiple checks will be made * options: - * is: Lenght must be exactly this value + * is: Lenght must be exactly this value * minimum: Lenght must be at least this value * maximum: Lenght must be at most this value * ------------------------ @@ -103,7 +103,7 @@ public function has_errors() { protected function validation_hooks() {} public function add_error($var, $msg) { - //if(!isset($this->errors[$var])) + //if(!isset($this->errors[$var])) //$this->errors[$var] = array(); $this->errors[$var][] = $msg; } @@ -145,11 +145,11 @@ protected function validate_numericality_of($var,$options=array()) { if(isset($options['allow_null']) && $options['allow_null'] && $this->$var == null) return; - if(isset($options['only_integers']) && $options['only_integers']) { + if(isset($options['only_integers']) && $options['only_integers']) { if(!is_numeric($this->$var) || preg_match('/\A[+-]?\d+\Z/',$this->$var)!=1) { $message = "måste vara ett heltal"; $this->add_error($var,isset($options['message'])?$options['message']:$message); - } + } } else if(!is_numeric($this->$var)){ $message = "måste vara ett nummer"; $this->add_error($var,isset($options['message'])?$options['message']:$message); @@ -190,10 +190,9 @@ protected function validate_length_of($var,$options=array()) { * minimum: Smallest allowed value * maximum: Largest allowed value */ - protected function validate_in_range($var,$options=array()) { if(isset($options['minimum']) && $options['minimum'] >= $this->$var) { - $message = "måste vara minst {$options['minimum']}"; + $message = "måste vara minst {$options['minimum']}"; $this->add_error($var,isset($options['message'])?$options['message']:$message); } if(isset($options['maximum']) && $options['maximum'] <= $this->$var) { From b26d90519615db816abd265bea9ea4aae358c767 Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Fri, 15 Feb 2013 22:23:34 +0100 Subject: [PATCH 16/75] make inclusive --- ValidatingBasicObject.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ValidatingBasicObject.php b/ValidatingBasicObject.php index 50e0a5e..c9533ca 100644 --- a/ValidatingBasicObject.php +++ b/ValidatingBasicObject.php @@ -191,11 +191,11 @@ protected function validate_length_of($var,$options=array()) { * maximum: Largest allowed value */ protected function validate_in_range($var,$options=array()) { - if(isset($options['minimum']) && $options['minimum'] >= $this->$var) { + if(isset($options['minimum']) && $options['minimum'] > $this->$var ) { $message = "måste vara minst {$options['minimum']}"; $this->add_error($var,isset($options['message'])?$options['message']:$message); } - if(isset($options['maximum']) && $options['maximum'] <= $this->$var) { + if(isset($options['maximum']) && $options['maximum'] < $this->$var) { $message = "får inte vara större än {$options['maximum']}"; $this->add_error($var,isset($options['message'])?$options['message']:$message); } From aa25c7368986428504fbfa9f14b669f56ce8301d Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Fri, 15 Feb 2013 22:25:39 +0100 Subject: [PATCH 17/75] kortare alias --- ValidatingBasicObject.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ValidatingBasicObject.php b/ValidatingBasicObject.php index c9533ca..cf4cfed 100644 --- a/ValidatingBasicObject.php +++ b/ValidatingBasicObject.php @@ -191,6 +191,9 @@ protected function validate_length_of($var,$options=array()) { * maximum: Largest allowed value */ protected function validate_in_range($var,$options=array()) { + if ( isset($options['min']) ) $options['minimum'] = $options['min']; + if ( isset($options['max']) ) $options['maximum'] = $options['max']; + if(isset($options['minimum']) && $options['minimum'] > $this->$var ) { $message = "måste vara minst {$options['minimum']}"; $this->add_error($var,isset($options['message'])?$options['message']:$message); From 05e59f1117d11cc7a009c974f73a68c1b8501fcc Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Fri, 15 Feb 2013 23:28:16 +0100 Subject: [PATCH 18/75] Don't allow setting of non-column attributes --- BasicObject.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/BasicObject.php b/BasicObject.php index bb48839..c8ba9ed 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -202,6 +202,16 @@ public function __construct($array = null, $exists=false) { if($exists && empty($array)) { throw new Exception("Can't create new instance marked as existing with an empty data array"); } + $columns = self::columns(static::table_name()); + + if(is_array($array)) { + foreach($array as $key => $value) { + if(!in_array($key, $columns)) { + unset($array[$key]); + } + } + } + $this->_exists = $exists; $this->_data = $array; } From 69a8586b73058a23c6e9fa618484e0114373284f Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Sat, 16 Feb 2013 00:26:33 +0100 Subject: [PATCH 19/75] cosmetic: remove trailing whitespace --- BasicObject.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index c8ba9ed..185d25f 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -493,7 +493,7 @@ public function delete() { * @return Object The Object specified by $id. */ public static function from_id($id){ - $id_name = static::id_name(); + $id_name = static::id_name(); return static::from_field($id_name, $id); } @@ -508,7 +508,7 @@ protected static function from_field($field, $value, $type='s'){ $field_name = $field; - $table_name = static::table_name(); + $table_name = static::table_name(); if(!self::in_table($field, $table_name)){ throw new Exception("No such column '$field' in table '$table_name'"); } @@ -575,7 +575,7 @@ public static function sum($field, $params = array()) { throw new Exception("No such column '$f' in table '".static::table_name()."'"); } $exp .= "`$f`"; - } + } $query = "SELECT SUM($exp) FROM ($query) q"; } else { if(!self::in_table($field, static::table_name())){ @@ -739,8 +739,8 @@ public static function selection($params = array(), $debug=false){ } private static function build_query($params, $select){ - $table_name = static::table_name(); - $id_name = static::id_name(); + $table_name = static::table_name(); + $id_name = static::id_name(); $joins = array(); $wheres = ''; $order = array(); @@ -749,7 +749,7 @@ private static function build_query($params, $select){ if(count($order) == 0 && strpos(strtolower($wheres),'order by') === false) { // Set default order - if(static::default_order() != null) + if(static::default_order() != null) $order[] = static::default_order(); } @@ -764,7 +764,7 @@ private static function build_query($params, $select){ $group = ""; break; } - $query .= + $query .= "FROM\n". " `".$table_name."`"; foreach($joins as $table => $join){ @@ -979,8 +979,8 @@ private static function handle_params($params, &$joins, &$wheres, &$order, &$tab * By default this method performs commit() on the object before it is returned, but that * can be turned of (see @param $options) * - * @param $array An assoc array (for example from postdata) with $field_name=>$value. - * If ["id"] or [id_name] is set the model is marked as existing, + * @param $array An assoc array (for example from postdata) with $field_name=>$value. + * If ["id"] or [id_name] is set the model is marked as existing, * otherwise it is treated as a new object. * * Note: To use this method with checkboxes a hidden field with the same name and value @@ -1007,7 +1007,7 @@ public static function update_attributes($array, $options=array()) { $obj = new static($array); //Change [id] to [id_name] if [id] is set but id_name()!='id' - if($obj->id_name() != "id" + if($obj->id_name() != "id" && isset($obj->_data['id']) && !is_null($obj->_data['id']) && !empty($obj->_data['id']) @@ -1018,7 +1018,7 @@ public static function update_attributes($array, $options=array()) { //Prevent errors where the id field has another name and ['id'] is null unset($obj->_data['id']); } - + $id = $obj->id; if($id!=null && $id!="") { @@ -1026,7 +1026,7 @@ public static function update_attributes($array, $options=array()) { $obj->_data = array_merge($old_obj->_data,$obj->_data); $obj->_exists = true; //Mark as existing } - + if(!isset($options["commit"]) || $options["commit"] == true) { $obj->commit(); } @@ -1146,7 +1146,7 @@ private static function fix_join($path, &$joins, $parent_columns, $parent){ $key = array_shift($path); if(!in_array($key, $columns)){ throw new Exception("No such column '$key' in table '$first'"); - } + } return $first.'`.`'.$key; } else { return self::fix_join($path, $joins, $columns, $first); @@ -1199,7 +1199,7 @@ private static function connection($table1, $table2) { `COLUMN_NAME`, `REFERENCED_TABLE_NAME`, `REFERENCED_COLUMN_NAME` - FROM + FROM `information_schema`.`table_constraints` join `information_schema`.`key_column_usage` using (`CONSTRAINT_NAME`, `CONSTRAINT_SCHEMA`) WHERE From a768e79e1c5171c3f0a8ef8aa97905bc32a19cf0 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Sat, 16 Feb 2013 00:54:20 +0100 Subject: [PATCH 20/75] Return clone from cache --- BasicObject.php | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 185d25f..f63e45f 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -217,11 +217,21 @@ public function __construct($array = null, $exists=false) { } /** - * Clone is called on the new object once cloning is complete + * Creates a duplicate with all the attributes from this instance, but with id set to null, and exist set to false + */ + public function duplicate() { + $dup = clone $this; + $dup->_exists = false; + $dup->_data[$this->id_name()]=null; + return $dup; + } + + /** + * Called after a clone is completed. + * Don't do anything, but with this one undefined __call get called instead */ public function __clone() { - $this->_exists = false; - $this->_data[$this->id_name()]=null; + } /** @@ -373,6 +383,19 @@ private function get_fresh_instance() { return array_shift($ret); } + private static function cache_clone(&$obj) { + if(is_array($obj)) { + $ret = array(); + foreach($obj as $k=>$v) { + $ret[$k] = clone $v; + } + } else if($obj != null) { + return clone $obj; + } else { + return null; + } + } + /** * Commits all fields to database. If this object was created with "new Object()" a new row * will be created in the table and this object will atempt to update itself with automagic values. @@ -503,7 +526,7 @@ protected static function from_field($field, $value, $type='s'){ static::validate_cache(); if(BasicObject::$_enable_cache && isset(static::$_from_field_cache[$field][$value])) { - return static::$_from_field_cache[$field][$value]; + return self::cache_clone(static::$_from_field_cache[$field][$value]); } $field_name = $field; @@ -535,7 +558,7 @@ protected static function from_field($field, $value, $type='s'){ if(BasicObject::$_enable_cache) { if(!isset(static::$_from_field_cache[$field_name])) static::$_from_field_cache[$field_name] = array(); - static::$_from_field_cache[$field_name][$value] = $object; + static::$_from_field_cache[$field_name][$value] = self::cache_clone($object); } return $object; @@ -686,7 +709,7 @@ public static function selection($params = array(), $debug=false){ if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); if(isset(static::$_selection_cache[$cache_string])) { - return static::$_selection_cache[$cache_string]; + return self::cache_clone( static::$_selection_cache[$cache_string]); } } @@ -732,7 +755,7 @@ public static function selection($params = array(), $debug=false){ $stmt->close(); if(BasicObject::$_enable_cache) { - static::$_selection_cache[$cache_string] = $ret; + static::$_selection_cache[$cache_string] = self::cache_clone($ret); } return $ret; From c26c389ac9be8fff11b24ba5a6a2efd25c693247 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 18 Feb 2013 19:14:34 +0100 Subject: [PATCH 21/75] Allow alias key "id" in data array to __construct --- BasicObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BasicObject.php b/BasicObject.php index f63e45f..a498f10 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -206,7 +206,7 @@ public function __construct($array = null, $exists=false) { if(is_array($array)) { foreach($array as $key => $value) { - if(!in_array($key, $columns)) { + if($key != "id" && !in_array($key, $columns)) { unset($array[$key]); } } From 818b0e4f8eeb164f60368b25e0dea4d45bc47fbe Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Sun, 3 Mar 2013 14:21:00 +0100 Subject: [PATCH 22/75] I accidentally a whole T_PRIVATE --- BasicObject.php | 1 + 1 file changed, 1 insertion(+) diff --git a/BasicObject.php b/BasicObject.php index 0d7278f..274b66f 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -394,6 +394,7 @@ private static function cache_clone(&$obj) { } else { return null; } + } private static function changed($old, $cur){ if ( $old != $cur ) return true; From c705445cd8f9a87bc90968acf80273c1a0c53c4f Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Fri, 8 Mar 2013 17:50:50 +0100 Subject: [PATCH 23/75] Fix from_field cache. static in base class does not by itself use late static binding, only if the derived class declared the same variable. Thus the from_field cache would collide if two tables had the same column name. For instance: $a = Event::from_id(1); $b = Row::from_id(1); var_dump($a); var_dump($b); Since both tables use "id" the results would collide and show up as the same instance. --- BasicObject.php | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 274b66f..66186ae 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -13,7 +13,7 @@ abstract class BasicObject { protected static $_local_cache_revision = 0; /* * [ - * 'field' => [ + * 'table:field' => [ * value => object * ] * ] @@ -539,15 +539,16 @@ public static function from_id($id){ protected static function from_field($field, $value, $type='s'){ global $db; - static::validate_cache(); + $field_name = $field; + $table_name = static::table_name(); + $cache_key = "$table_name:$field_name"; - if(BasicObject::$_enable_cache && isset(static::$_from_field_cache[$field][$value])) { - return self::cache_clone(static::$_from_field_cache[$field][$value]); + /* test if a cached result exists */ + static::validate_cache(); + if(BasicObject::$_enable_cache && isset(BasicObject::$_from_field_cache[$cache_key][$value])){ + return self::cache_clone(BasicObject::$_from_field_cache[$cache_key][$value]); } - $field_name = $field; - - $table_name = static::table_name(); if(!self::in_table($field, $table_name)){ throw new Exception("No such column '$field' in table '$table_name'"); } @@ -571,10 +572,10 @@ protected static function from_field($field, $value, $type='s'){ } $stmt->close(); - if(BasicObject::$_enable_cache) { - if(!isset(static::$_from_field_cache[$field_name])) static::$_from_field_cache[$field_name] = array(); - - static::$_from_field_cache[$field_name][$value] = self::cache_clone($object); + /* store result in cache */ + if(BasicObject::$_enable_cache){ + if(!isset(BasicObject::$_from_field_cache[$cache_key])) BasicObject::$_from_field_cache[$cache_key] = array(); + BasicObject::$_from_field_cache[$cache_key][$value] = self::cache_clone($object); } return $object; @@ -1301,7 +1302,7 @@ public function __toString() { protected static function validate_cache() { if(BasicObject::$_enable_cache && BasicObject::$_global_cache_revision > static::$_local_cache_revision) { - static::$_from_field_cache = array(); + BasicObject::$_from_field_cache = array(); static::$_selection_cache = array(); static::$_sum_cache = array(); static::$_count_cache = array(); From f113721939235f82b49fe01fee995e2d59470f41 Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Fri, 8 Mar 2013 18:07:30 +0100 Subject: [PATCH 24/75] Replace static:: with BasicObject:: for clarity. --- BasicObject.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 66186ae..28b11c6 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -590,8 +590,8 @@ public static function sum($field, $params = array()) { $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); - if(isset(static::$_sum_cache[$cache_string])) { - return static::$_sum_cache[$cache_string]; + if(isset(BasicObject::$_sum_cache[$cache_string])) { + return BasicObject::$_sum_cache[$cache_string]; } } @@ -637,7 +637,7 @@ public static function sum($field, $params = array()) { $stmt->close(); if(BasicObject::$_enable_cache) { - static::$_sum_cache[$cache_string] = $result; + BasicObject::$_sum_cache[$cache_string] = $result; } return $result; @@ -655,8 +655,8 @@ public static function count($params = array(), $debug = false){ $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); - if(isset(static::$_count_cache[$cache_string])) { - return static::$_count_cache[$cache_string]; + if(isset(BasicObject::$_count_cache[$cache_string])) { + return BasicObject::$_count_cache[$cache_string]; } } @@ -679,7 +679,7 @@ public static function count($params = array(), $debug = false){ $stmt->close(); if(BasicObject::$_enable_cache) { - static::$_count_cache[$cache_string] = $result; + BasicObject::$_count_cache[$cache_string] = $result; } return $result; @@ -725,8 +725,8 @@ public static function selection($params = array(), $debug=false){ $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); - if(isset(static::$_selection_cache[$cache_string])) { - return self::cache_clone( static::$_selection_cache[$cache_string]); + if(isset(BasicObject::$_selection_cache[$cache_string])) { + return self::cache_clone( BasicObject::$_selection_cache[$cache_string]); } } @@ -772,7 +772,7 @@ public static function selection($params = array(), $debug=false){ $stmt->close(); if(BasicObject::$_enable_cache) { - static::$_selection_cache[$cache_string] = self::cache_clone($ret); + BasicObject::$_selection_cache[$cache_string] = self::cache_clone($ret); } return $ret; @@ -1301,12 +1301,12 @@ public function __toString() { } protected static function validate_cache() { - if(BasicObject::$_enable_cache && BasicObject::$_global_cache_revision > static::$_local_cache_revision) { + if(BasicObject::$_enable_cache && BasicObject::$_global_cache_revision > BasicObject::$_local_cache_revision) { BasicObject::$_from_field_cache = array(); - static::$_selection_cache = array(); - static::$_sum_cache = array(); - static::$_count_cache = array(); - static::$_local_cache_revision = BasicObject::$_global_cache_revision; + BasicObject::$_selection_cache = array(); + BasicObject::$_sum_cache = array(); + BasicObject::$_count_cache = array(); + BasicObject::$_local_cache_revision = BasicObject::$_global_cache_revision; } } } From 51149452afaf9d9883f0db7046a7f1f0ab8b3cd8 Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Fri, 8 Mar 2013 18:10:09 +0100 Subject: [PATCH 25/75] Since cache is global there is no need for local/global revision. --- BasicObject.php | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 28b11c6..7d0535c 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -9,8 +9,6 @@ abstract class BasicObject { protected $_old_key = array(); protected $_exists; - protected static $_global_cache_revision = 0; - protected static $_local_cache_revision = 0; /* * [ * 'table:field' => [ @@ -54,7 +52,10 @@ public static function enable_cache() { } public static function invalidate_cache() { - ++BasicObject::$_global_cache_revision; + BasicObject::$_from_field_cache = array(); + BasicObject::$_selection_cache = array(); + BasicObject::$_sum_cache = array(); + BasicObject::$_count_cache = array(); } /** @@ -544,7 +545,6 @@ protected static function from_field($field, $value, $type='s'){ $cache_key = "$table_name:$field_name"; /* test if a cached result exists */ - static::validate_cache(); if(BasicObject::$_enable_cache && isset(BasicObject::$_from_field_cache[$cache_key][$value])){ return self::cache_clone(BasicObject::$_from_field_cache[$cache_key][$value]); } @@ -585,8 +585,6 @@ public static function sum($field, $params = array()) { global $db; $data = static::build_query($params, '*'); - static::validate_cache(); - $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); @@ -720,8 +718,6 @@ public static function selection($params = array(), $debug=false){ global $db; $data = self::build_query($params, '*'); - static::validate_cache(); - $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); @@ -1299,16 +1295,7 @@ public function __toString() { } return get_class($this). "{".implode(", ",$content)."}"; } - - protected static function validate_cache() { - if(BasicObject::$_enable_cache && BasicObject::$_global_cache_revision > BasicObject::$_local_cache_revision) { - BasicObject::$_from_field_cache = array(); - BasicObject::$_selection_cache = array(); - BasicObject::$_sum_cache = array(); - BasicObject::$_count_cache = array(); - BasicObject::$_local_cache_revision = BasicObject::$_global_cache_revision; - } - } } + class UndefinedMemberException extends Exception{} class UndefinedFunctionException extends Exception{} From 15dfdbdaa06f50db46faaeb0f3bda1c601158804 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Sun, 10 Mar 2013 23:25:09 +0100 Subject: [PATCH 26/75] Add Readme with dependency list for testing --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..da3cb53 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +BasicObject +========== + +Dependencies (Only for running tests) +-------------------- + +* PHPUnit: https://github.com/sebastianbergmann/phpunit/ +* phpunit/DbUnit From f7eefcf8486140137bfd410d30409c3a0e909ff2 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 00:00:26 +0100 Subject: [PATCH 27/75] Add structure for doing tests --- .gitignore | 1 + README.md | 1 - tests/database.php | 37 +++++++++++++++++++++++++++++++++++++ tests/db.sql | 19 +++++++++++++++++++ tests/includes.php | 14 ++++++++++++++ tests/models/Model1.php | 7 +++++++ tests/models/Model2.php | 7 +++++++ tests/settings.php.sample | 9 +++++++++ tests/setup.php | 22 ++++++++++++++++++++++ 9 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 tests/database.php create mode 100644 tests/db.sql create mode 100644 tests/includes.php create mode 100644 tests/models/Model1.php create mode 100644 tests/models/Model2.php create mode 100644 tests/settings.php.sample create mode 100755 tests/setup.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d91585e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tests/settings.php diff --git a/README.md b/README.md index da3cb53..6701b39 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,3 @@ Dependencies (Only for running tests) -------------------- * PHPUnit: https://github.com/sebastianbergmann/phpunit/ -* phpunit/DbUnit diff --git a/tests/database.php b/tests/database.php new file mode 100644 index 0000000..3b7bf4a --- /dev/null +++ b/tests/database.php @@ -0,0 +1,37 @@ +select_db($db_settings['database']); +} + +function db_clean() { + global $db; + $db->query("TRUNCATE TABLE *"); +} + +function db_run_file($filename) { + global $db; + $handle = fopen(realpath(dirname(__FILE__) . "/" . $filename ), "r"); + $contents = fread($handle, filesize($filename)); + fclose($handle); + + $db->multi_query($contents); +} diff --git a/tests/db.sql b/tests/db.sql new file mode 100644 index 0000000..8b95ffa --- /dev/null +++ b/tests/db.sql @@ -0,0 +1,19 @@ +CREATE TABLE IF NOT EXISTS `model1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `int1` int(11) NOT NULL, + `str1` varchar(64) NOT NULL, + `model2_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `model2_id` (`model2_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; + +CREATE TABLE IF NOT EXISTS `model2` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `int1` int(11) DEFAULT NULL, + `str1` varchar(128) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; + +ALTER TABLE `model1` + ADD CONSTRAINT `model1_ibfk_1` FOREIGN KEY (`model2_id`) REFERENCES `model2` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; + diff --git a/tests/includes.php b/tests/includes.php new file mode 100644 index 0000000..e11a683 --- /dev/null +++ b/tests/includes.php @@ -0,0 +1,14 @@ +'localhost', + 'port'=>'3306', + 'username'=>'root', + 'password'=>'', + 'database'=>'basicobject-testing', + 'charset'=>'utf8' +); diff --git a/tests/setup.php b/tests/setup.php new file mode 100755 index 0000000..08e5f85 --- /dev/null +++ b/tests/setup.php @@ -0,0 +1,22 @@ +#!/usr/bin/php +query("DROP DATABASE `{$db_settings['database']}` IF EXISTS"); + +echo "Creating database\n"; + +$db->query("CREATE DATABASE `{$db_settings['database']}`"); + +echo "Importing tables\n"; + +db_run_file("db.sql"); + +echo "Done\n"; + + From 4cd7d33c5fed740567e85ac56808a4b1ff2662fd Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 00:56:42 +0100 Subject: [PATCH 28/75] Add more structure for tests and first test --- tests/DatabaseTestCase.php | 15 +++++++++++++++ tests/MC.php | 28 ++++++++++++++++++++++++++++ tests/database.php | 8 +++----- tests/db.sql | 8 ++++---- tests/includes.php | 14 +++++++------- tests/settings.php.sample | 5 +++++ tests/setup.php | 10 ++++++++-- tests/suites/BasicTest.php | 24 ++++++++++++++++++++++++ 8 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 tests/DatabaseTestCase.php create mode 100644 tests/MC.php create mode 100644 tests/suites/BasicTest.php diff --git a/tests/DatabaseTestCase.php b/tests/DatabaseTestCase.php new file mode 100644 index 0000000..a5fe0ae --- /dev/null +++ b/tests/DatabaseTestCase.php @@ -0,0 +1,15 @@ +connect($memcache_settings['host'], $memcache_settings['port']) === false) { + trigger_error("Unable to connect to memcache at ".$memcache_settings['host']." on port ".$memcache_settings['port'], E_USER_WARNING); + throw new Exception("Failed to connect"); + } + } else { + throw new Exception("Failed to connect"); + } + } + + public static function get_instance() { + if(empty(self::$instance)) { + self::$instance = new MC(); + } + return self::$instance; + } +} diff --git a/tests/database.php b/tests/database.php index 3b7bf4a..1f43cf8 100644 --- a/tests/database.php +++ b/tests/database.php @@ -13,10 +13,6 @@ $db_settings['port'] ); -function db_prepare_testing() { - db_select_database(); -} - function db_select_database() { global $db, $db_settings; $db->select_db($db_settings['database']); @@ -33,5 +29,7 @@ function db_run_file($filename) { $contents = fread($handle, filesize($filename)); fclose($handle); - $db->multi_query($contents); + if(!$db->multi_query($contents)) { + echo "Failed to execute query: {$db->error}\n"; + } } diff --git a/tests/db.sql b/tests/db.sql index 8b95ffa..0aaeee7 100644 --- a/tests/db.sql +++ b/tests/db.sql @@ -1,8 +1,8 @@ CREATE TABLE IF NOT EXISTS `model1` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `int1` int(11) NOT NULL, - `str1` varchar(64) NOT NULL, - `model2_id` int(11) NOT NULL, + `int1` int(11), + `str1` varchar(64), + `model2_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `model2_id` (`model2_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; @@ -10,7 +10,7 @@ CREATE TABLE IF NOT EXISTS `model1` ( CREATE TABLE IF NOT EXISTS `model2` ( `id` int(11) NOT NULL AUTO_INCREMENT, `int1` int(11) DEFAULT NULL, - `str1` varchar(128) NOT NULL, + `str1` varchar(128), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; diff --git a/tests/includes.php b/tests/includes.php index e11a683..aaee04a 100644 --- a/tests/includes.php +++ b/tests/includes.php @@ -1,14 +1,14 @@ 'basicobject-testing', 'charset'=>'utf8' ); + +$memcache_settings = array( + 'host' => 'localhost', + 'port' => 11211 +); diff --git a/tests/setup.php b/tests/setup.php index 08e5f85..c0ec1cd 100755 --- a/tests/setup.php +++ b/tests/setup.php @@ -3,11 +3,14 @@ include realpath(dirname(__FILE__)) . "/database.php"; +include realpath(dirname(__FILE__)) . "/MC.php"; +include realpath(dirname(__FILE__)) . "/../BasicObject.php"; + echo "Setting up database {$db_settings['database']} for testing\n"; echo "Dropping database if exists\n"; -$db->query("DROP DATABASE `{$db_settings['database']}` IF EXISTS"); +$db->query("DROP DATABASE `{$db_settings['database']}`"); echo "Creating database\n"; @@ -15,8 +18,11 @@ echo "Importing tables\n"; +db_select_database(); + db_run_file("db.sql"); +echo "Clearing up in memcached\n"; +BasicObject::clear_structure_cache(MC::get_instance()); echo "Done\n"; - diff --git a/tests/suites/BasicTest.php b/tests/suites/BasicTest.php new file mode 100644 index 0000000..caf8f0f --- /dev/null +++ b/tests/suites/BasicTest.php @@ -0,0 +1,24 @@ +int1 = 1; + $model1->str1 = "Test"; + $model1->commit(); + + $this->assertNotNull($model1->id); + + $id = $model1->id; + unset($model1); + + $model1 = Model1::from_id($id); + + $this->assertEquals($model1->int1, 1); + $this->assertEquals($model1->str1, "Test"); + } +} + From 76f360c0497e5a7e4e691822ee14396802554277 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 02:00:11 +0100 Subject: [PATCH 29/75] Cache NULL results too --- BasicObject.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 7d0535c..8cf862d 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -397,6 +397,10 @@ private static function cache_clone(&$obj) { } } + private static function in_cache(&$cache, $key) { + return isset($cache) && array_key_exists($key, $cache); + } + private static function changed($old, $cur){ if ( $old != $cur ) return true; if ( $old === null && $cur !== null ) return true; @@ -545,7 +549,7 @@ protected static function from_field($field, $value, $type='s'){ $cache_key = "$table_name:$field_name"; /* test if a cached result exists */ - if(BasicObject::$_enable_cache && isset(BasicObject::$_from_field_cache[$cache_key][$value])){ + if(BasicObject::$_enable_cache && self::in_cache(BasicObject::$_from_field_cache[$cache_key], $value)){ return self::cache_clone(BasicObject::$_from_field_cache[$cache_key][$value]); } @@ -588,7 +592,7 @@ public static function sum($field, $params = array()) { $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); - if(isset(BasicObject::$_sum_cache[$cache_string])) { + if(self::in_cache(BasicObject::$_sum_cache,$cache_string)) { return BasicObject::$_sum_cache[$cache_string]; } } @@ -653,7 +657,7 @@ public static function count($params = array(), $debug = false){ $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); - if(isset(BasicObject::$_count_cache[$cache_string])) { + if(self::in_cache(BasicObject::$_count_cache,$cache_string)) { return BasicObject::$_count_cache[$cache_string]; } } @@ -721,7 +725,7 @@ public static function selection($params = array(), $debug=false){ $cache_string = null; if(BasicObject::$_enable_cache) { $cache_string = implode(";", $data); - if(isset(BasicObject::$_selection_cache[$cache_string])) { + if(self::in_cache(BasicObject::$_selection_cache,$cache_string)) { return self::cache_clone( BasicObject::$_selection_cache[$cache_string]); } } From 7b5951db699b5dd0d90caf0575a016f511bb5e03 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 02:51:48 +0100 Subject: [PATCH 30/75] Actually return clone array of objects --- BasicObject.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BasicObject.php b/BasicObject.php index 8cf862d..c7a9e1c 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -390,7 +390,8 @@ private static function cache_clone(&$obj) { foreach($obj as $k=>$v) { $ret[$k] = clone $v; } - } else if($obj != null) { + return $ret; + } else if($obj !== null) { return clone $obj; } else { return null; From 902ddd696df3a970aafed0db542b56f7722e1701 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 13:40:22 +0100 Subject: [PATCH 31/75] Add script for easy running of tests --- tests/tests.sh | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 tests/tests.sh diff --git a/tests/tests.sh b/tests/tests.sh new file mode 100755 index 0000000..d7e294c --- /dev/null +++ b/tests/tests.sh @@ -0,0 +1,2 @@ +#!/bin/sh +phpunit --color suites From f2636a6e1d63b1831fe4ad8c1907196d4d56898c Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 13:40:37 +0100 Subject: [PATCH 32/75] Fix problems with multiple test suites --- tests/DatabaseTestCase.php | 6 +++++- tests/database.php | 20 +++++++++++--------- tests/setup.php | 2 ++ tests/suites/BasicTest.php | 2 +- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/tests/DatabaseTestCase.php b/tests/DatabaseTestCase.php index a5fe0ae..7421a8f 100644 --- a/tests/DatabaseTestCase.php +++ b/tests/DatabaseTestCase.php @@ -2,7 +2,7 @@ class DatabaseTestCase extends PHPUnit_Framework_TestCase { public static function setUpBeforeClass() { - db_select_database(); + db_create(true); BasicObject::enable_structure_cache(MC::get_instance()); //make sure cache is only on when explicitly set BasicObject::disable_cache(); @@ -12,4 +12,8 @@ public function setUp() { BasicObject::$output_htmlspecialchars = false; db_clean(); } + + public static function tearDownAfterClass() { + BasicObject::clear_structure_cache(MC::get_instance()); + } } diff --git a/tests/database.php b/tests/database.php index 1f43cf8..b428909 100644 --- a/tests/database.php +++ b/tests/database.php @@ -2,16 +2,18 @@ include realpath(dirname(__FILE__)) . "/settings.php"; -global $db; -/* Database */ -$db = new mysqli( - $db_settings['host'], - $db_settings['username'], - $db_settings['password'], - "", - $db_settings['port'] -); +function db_create($select_db = false) { + global $db, $db_settings; + /* Database */ + $db = new mysqli( + $db_settings['host'], + $db_settings['username'], + $db_settings['password'], + $select_db ? $db_settings['database'] : "", + $db_settings['port'] + ); +} function db_select_database() { global $db, $db_settings; diff --git a/tests/setup.php b/tests/setup.php index c0ec1cd..ac96cd1 100755 --- a/tests/setup.php +++ b/tests/setup.php @@ -8,6 +8,8 @@ echo "Setting up database {$db_settings['database']} for testing\n"; +db_create(); + echo "Dropping database if exists\n"; $db->query("DROP DATABASE `{$db_settings['database']}`"); diff --git a/tests/suites/BasicTest.php b/tests/suites/BasicTest.php index caf8f0f..c0f511f 100644 --- a/tests/suites/BasicTest.php +++ b/tests/suites/BasicTest.php @@ -1,6 +1,6 @@ Date: Mon, 11 Mar 2013 13:41:08 +0100 Subject: [PATCH 33/75] Correct colors arg --- tests/tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests.sh b/tests/tests.sh index d7e294c..a35daf3 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -1,2 +1,2 @@ #!/bin/sh -phpunit --color suites +phpunit --colors suites From f1aa86fc0d657718e01d8750a142ff54e7d0e4ef Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 13:48:41 +0100 Subject: [PATCH 34/75] Correctly handle multiple tests make phpunit ignore the global $db --- tests/DatabaseTestCase.php | 3 +++ tests/database.php | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/tests/DatabaseTestCase.php b/tests/DatabaseTestCase.php index 7421a8f..e21c134 100644 --- a/tests/DatabaseTestCase.php +++ b/tests/DatabaseTestCase.php @@ -1,6 +1,8 @@ error}\n"; } } + +function db_close() { + global $db; + $db->close(); +} From ac2c5eb0c3399439b46cb3e4aa017140c2c91b89 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 14:18:34 +0100 Subject: [PATCH 35/75] Create database each class setup --- tests/DatabaseTestCase.php | 3 +-- tests/database.php | 34 +++++++++++++++++++++++++--------- tests/setup.php | 30 ------------------------------ 3 files changed, 26 insertions(+), 41 deletions(-) delete mode 100755 tests/setup.php diff --git a/tests/DatabaseTestCase.php b/tests/DatabaseTestCase.php index e21c134..aac81b8 100644 --- a/tests/DatabaseTestCase.php +++ b/tests/DatabaseTestCase.php @@ -4,7 +4,7 @@ class DatabaseTestCase extends PHPUnit_Framework_TestCase { protected $backupGlobalsBlacklist = array('db'); public static function setUpBeforeClass() { - db_create(true); + db_init(); BasicObject::enable_structure_cache(MC::get_instance()); //make sure cache is only on when explicitly set BasicObject::disable_cache(); @@ -12,7 +12,6 @@ public static function setUpBeforeClass() { public function setUp() { BasicObject::$output_htmlspecialchars = false; - db_clean(); } public static function tearDownAfterClass() { diff --git a/tests/database.php b/tests/database.php index 2f4539d..4cc8c1e 100644 --- a/tests/database.php +++ b/tests/database.php @@ -2,17 +2,25 @@ include realpath(dirname(__FILE__)) . "/settings.php"; - -function db_create($select_db = false) { +/* + * Setup database for testing + */ +function db_init() { global $db, $db_settings; /* Database */ $db = new mysqli( $db_settings['host'], $db_settings['username'], $db_settings['password'], - $select_db ? $db_settings['database'] : "", + "", $db_settings['port'] ); + + $db->query("DROP DATABASE `{$db_settings['database']}`"); + $db->query("CREATE DATABASE `{$db_settings['database']}`"); + db_select_database(); + db_run_file("db.sql"); + BasicObject::clear_structure_cache(MC::get_instance()); } function db_select_database() { @@ -20,11 +28,6 @@ function db_select_database() { $db->select_db($db_settings['database']); } -function db_clean() { - global $db; - $db->query("TRUNCATE TABLE *"); -} - function db_run_file($filename) { global $db; $handle = fopen(realpath(dirname(__FILE__) . "/" . $filename ), "r"); @@ -32,7 +35,20 @@ function db_run_file($filename) { fclose($handle); if(!$db->multi_query($contents)) { - echo "Failed to execute query: {$db->error}\n"; + throw new Exception("Failed to execute query: {$db->error}\n"); + } + + + do { + $result = $db->use_result(); + if($result) $result->free(); + } while($db->next_result()); +} + +function db_query($query) { + global $db; + if(!$db->query($db)) { + throw new Exception("Failed execute manual query '$query': ".$db->error); } } diff --git a/tests/setup.php b/tests/setup.php deleted file mode 100755 index ac96cd1..0000000 --- a/tests/setup.php +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/php -query("DROP DATABASE `{$db_settings['database']}`"); - -echo "Creating database\n"; - -$db->query("CREATE DATABASE `{$db_settings['database']}`"); - -echo "Importing tables\n"; - -db_select_database(); - -db_run_file("db.sql"); - -echo "Clearing up in memcached\n"; -BasicObject::clear_structure_cache(MC::get_instance()); -echo "Done\n"; - From 60f7723e285d5748b3d81bd8be410528f8ca1506 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 14:19:28 +0100 Subject: [PATCH 36/75] Drop database on close --- tests/database.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/database.php b/tests/database.php index 4cc8c1e..31d05a3 100644 --- a/tests/database.php +++ b/tests/database.php @@ -53,6 +53,7 @@ function db_query($query) { } function db_close() { - global $db; + global $db, $db_settings; + $db->query("DROP DATABASE `{$db_settings['database']}`"); $db->close(); } From 85456176edc55c7b6aa78c843bbb41ec9f6d66d0 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 14:24:40 +0100 Subject: [PATCH 37/75] Add from_id test --- tests/suites/BasicTest.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/suites/BasicTest.php b/tests/suites/BasicTest.php index c0f511f..37e5b9d 100644 --- a/tests/suites/BasicTest.php +++ b/tests/suites/BasicTest.php @@ -4,6 +4,21 @@ class BasicTest extends DatabaseTestCase { + public function testFromId() { + global $db; + if(!$db->query("INSERT INTO `model1` SET `int1` = 5, `str1` = 'foobar'")) { + throw new Exception("Failed to insert model by manual query: ".$db->error); + } + $id = $db->insert_id; + $obj = Model1::from_id($id); + $this->assertNotNull($obj); + $this->assertEquals($obj->int1, 5); + $this->assertEquals($obj->str1, "foobar"); + } + + /** + * @depends testFromId + */ public function testInsert() { $model1 = new Model1(); $model1->int1 = 1; @@ -20,5 +35,24 @@ public function testInsert() { $this->assertEquals($model1->int1, 1); $this->assertEquals($model1->str1, "Test"); } + + /** + * @depends testFromId + */ + public function testArrayInsert() { + $model1 = new Model1(array('int1'=>1, 'str1' => "Test")); + $model1->commit(); + + $this->assertNotNull($model1->id); + + $id = $model1->id; + unset($model1); + + $model1 = Model1::from_id($id); + + $this->assertEquals($model1->int1, 1); + $this->assertEquals($model1->str1, "Test"); + } + } From 5de8120a5c56f586276d581a6548588d7a8e69fb Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 16:49:27 +0100 Subject: [PATCH 38/75] Add Blueprint-class for creating model instances --- tests/Blueprint.php | 146 +++++++++++++++++++++++++++++++++++ tests/README.md | 15 ++++ tests/blueprints/Model1.json | 6 ++ tests/blueprints/Model2.json | 6 ++ tests/blueprints/README.md | 127 ++++++++++++++++++++++++++++++ tests/includes.php | 1 + 6 files changed, 301 insertions(+) create mode 100644 tests/Blueprint.php create mode 100644 tests/README.md create mode 100644 tests/blueprints/Model1.json create mode 100644 tests/blueprints/Model2.json create mode 100644 tests/blueprints/README.md diff --git a/tests/Blueprint.php b/tests/Blueprint.php new file mode 100644 index 0000000..17c6c83 --- /dev/null +++ b/tests/Blueprint.php @@ -0,0 +1,146 @@ +create($set, $name, $commit); + } + + private static $blueprints = array(); + + private static function find_blueprint($class) { + + if(isset(Blueprint::$blueprints[$class])) return Blueprint::$blueprints[$class]; + + $dir = realpath(dirname(__FILE__) . "/" . Blueprint::$blueprints_dir) . "/" ; + if(file_exists("$dir/$class.json")) { + Blueprint::$blueprints[$class] = new Blueprint($class, "$dir/$class.json"); + return Blueprint::$blueprints[$class]; + } else { + throw new BlueprintException("Couldn't find blueprint: $dir/$class.json"); + } + } + + private $class_name, $data; + + private function create($set, $name, $commit) { + if(!isset($this->data[$name])) { + throw new BlueprintException("Unknow blueprint '$name' for {$this->class_name}"); + } + $data = array_merge($this->data[$name], $set); + + $attr = array( + 'sn' => Blueprint::$sn++ + ); + + $class_name = $this->class_name; + + $obj = new $class_name; + + foreach($data as $key => $value) { + if(is_string($value)) { + $obj->$key = preg_replace_callback("/#\{(.+?)\}/", function($matches) use ($attr, $data) { + $k = $matches[1]; + $replace = false; + if(isset($attr[$k])) { + $replace = $attr[$k]; + } else { + $replace = $obj->$k; + } + return $replace; + }, $value); + } else if(is_array($value)) { + $blueprint = "default"; + $class = $key; + $values = array(); + if(isset($value['blueprint'])) { + $blueprint = $value['blueprint']; + unset($value['blueprint']); + } + + if(isset($value['class'])) { + $class = $value['class']; + unset($value['class']); + } + + if(isset($value['values'])) { + $values = $value['values']; + unset($value['values']); + } + + $values = array_merge($values, $value); + $obj->$key = Blueprint::make($class, $blueprint, $values, true); + } else { + $obj->$key = $value; + } + } + + if($commit) $obj->commit(); + + return $obj; + } + + private function __construct($class_name, $path) { + $this->class_name = $class_name; + + $contents = file_get_contents($path); + + $contents = preg_replace('/^(\s+)(\w+):/m', '$1"$2":', $contents); + + var_dump($contents); + + $this->data = json_decode($contents, true); + + if($this->data === NULL) { + // Define the errors. + $constants = get_defined_constants(true); + $json_errors = array(); + foreach ($constants["json"] as $name => $value) { + if (!strncmp($name, "JSON_ERROR_", 11)) { + $json_errors[$value] = $name; + } + } + + throw new BlueprintException("JSON parse error: {$json_errors[json_last_error()]}.\nParsed source: \n" . var_export($contents, true)); + } + } +} + +class BlueprintException extends Exception {} diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..8585cf5 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,15 @@ +Tests +===== + +To run the tests: + + ./tests.sh + +To create new tests, add files to suites/ (see exists tests for examples) + +Blueprints +======= + +To ease creation of tests there are a Blueprint-class for creating models. +Documentation on that is located in the blueprints-directory. +I recommend using Blueprints for your own projects BO-related tests too. diff --git a/tests/blueprints/Model1.json b/tests/blueprints/Model1.json new file mode 100644 index 0000000..5bf274b --- /dev/null +++ b/tests/blueprints/Model1.json @@ -0,0 +1,6 @@ +{ + default: { + int1: "100#{sn}", + str1: "str-#{sn}" + } +} diff --git a/tests/blueprints/Model2.json b/tests/blueprints/Model2.json new file mode 100644 index 0000000..5a8797a --- /dev/null +++ b/tests/blueprints/Model2.json @@ -0,0 +1,6 @@ +{ + default: { + int1: "200#{sn}", + str1: "A String #{sn}" + } +} diff --git a/tests/blueprints/README.md b/tests/blueprints/README.md new file mode 100644 index 0000000..e7f74fe --- /dev/null +++ b/tests/blueprints/README.md @@ -0,0 +1,127 @@ +Introduction +====== +Blueprints are a handy way to create models for your tests. + +Usage +======== + +Blueprints +---------- +For each class you want to have a blueprint, create a file {class_name}.json here. +(ex for class "User" create "User.json") + +A simple blueprint might look like this: + + _blueprints/User.json_ + + { + default: { + username: "Foobar", + real_name: "Foo Bar" + } + } + +You can now create a user with: + + Blueprint::make('User'); + +The "default" is the name of the blueprint. You should always have at least a default blueprint for each model, +but you can create more blueprints with different names, to use in different situations, eg: + + { + default: { + ... + }, + foobar: { + ... + }, + baz: { + ... + } + +To use a named blueprint instead of the default, send the name as a argument to make: + + Blueprint::make('User', 'foobar'); + +You can also override the value set by the blueprint by sending new values as a array to make: + + Blueprint::make('User', array('username' => 'Baz')); + +By default make commits the model to the database, but you can tell it not to: + + Blueprint::make('User', false); + +You can use all or none of the optional arguments (name, value, commit) to make at any call, +and they can be in any order, but this order is recommended: + + Blueprint::make('User', {name}, {values}, {commit}) + +Unique Attributes +--------------- + +For attributes that need to be unique you can add #{sn} to the value to get a unique serial number: + + { + default: { + username: "User-#{sn}", + ... + } + } + +The sn remains the same for the whole object + +Reusing attribute values +----------------- + +You can also use #{other_field_name} which will yield the value of that field. Note that +all fields are set in the order they are defined, so you can only refeere to a previously declared value: + + { + default: { + username: "User-#{sn}", + foobar: "#{username}" + } + } + +Associations +--------------- + +If your object have associations with other objects, you can do like this: + + { + default: { + Model2: {} + } + } + +This will set the field Model2 to a new blueprint instance of the class Model2. +You can also specify attributes: +* blueprint: The name of the blueprint to use +* class: The name of the other class +* values: Values to set + +Any other key/value-pair will be used as values as well, so this works: + + other_model: { + blueprint: 'test', + class: "Model2", + derp: "Foobar" + } + +Thus you only need to use the values field if you need to specify a field named blueprint, class or values. + +JSON modifications +----------- +Unfortunatly foo: "bar" is not correct json syntax, the correct way to do this would be "foo": "bar", +but it's just annoying to have to write the extra quotation-marks for each attributes. + +To prevent errors this is though only done if the attribute is on the beginning of the row, so this works: + + foo: "bar", + baz: "derp" + +But this will give a syntax error: + + foo: {class: "bar", blueprint: "derp"} + + diff --git a/tests/includes.php b/tests/includes.php index aaee04a..105389a 100644 --- a/tests/includes.php +++ b/tests/includes.php @@ -7,6 +7,7 @@ include realpath(dirname(__FILE__)) . "/MC.php"; include realpath(dirname(__FILE__)) . "/../BasicObject.php"; include realpath(dirname(__FILE__)) . "/../ValidatingBasicObject.php"; +include realpath(dirname(__FILE__)) . "/Blueprint.php"; include realpath(dirname(__FILE__)) . "/DatabaseTestCase.php"; foreach(glob(realpath(dirname(__FILE__)) . "/models/*.php") as $filename) { From 117ceaf4411203eb49590e9bf2caad1816c9e326 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 17:03:02 +0100 Subject: [PATCH 39/75] Use phpunit.xml instead of shellscript --- tests/README.md | 5 +++-- tests/phpunit.xml | 11 +++++++++++ tests/suites/{ => BasicObject}/BasicTest.php | 2 -- tests/tests.sh | 2 -- 4 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 tests/phpunit.xml rename tests/suites/{ => BasicObject}/BasicTest.php (95%) delete mode 100755 tests/tests.sh diff --git a/tests/README.md b/tests/README.md index 8585cf5..dc0fec3 100644 --- a/tests/README.md +++ b/tests/README.md @@ -3,9 +3,10 @@ Tests To run the tests: - ./tests.sh + phpunit -To create new tests, add files to suites/ (see exists tests for examples) +To create new tests, add files to suites/ (see exists tests for examples), +and optionally edit phpunit.xml if you create a new suite Blueprints ======= diff --git a/tests/phpunit.xml b/tests/phpunit.xml new file mode 100644 index 0000000..1f3a5e9 --- /dev/null +++ b/tests/phpunit.xml @@ -0,0 +1,11 @@ + + + + + suites/BasicObject/BasicTest.php + + + + diff --git a/tests/suites/BasicTest.php b/tests/suites/BasicObject/BasicTest.php similarity index 95% rename from tests/suites/BasicTest.php rename to tests/suites/BasicObject/BasicTest.php index 37e5b9d..8bd0723 100644 --- a/tests/suites/BasicTest.php +++ b/tests/suites/BasicObject/BasicTest.php @@ -1,7 +1,5 @@ Date: Mon, 11 Mar 2013 17:03:15 +0100 Subject: [PATCH 40/75] Remove debug stuff --- tests/Blueprint.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Blueprint.php b/tests/Blueprint.php index 17c6c83..13a3cf2 100644 --- a/tests/Blueprint.php +++ b/tests/Blueprint.php @@ -124,8 +124,6 @@ private function __construct($class_name, $path) { $contents = preg_replace('/^(\s+)(\w+):/m', '$1"$2":', $contents); - var_dump($contents); - $this->data = json_decode($contents, true); if($this->data === NULL) { From c7db86f5ec9db1ba11d118de95b74509404a582d Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 17:03:28 +0100 Subject: [PATCH 41/75] Don't drop database when done Makes it easier to study the dbstructure for writing test --- tests/database.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/database.php b/tests/database.php index 31d05a3..caac56f 100644 --- a/tests/database.php +++ b/tests/database.php @@ -54,6 +54,5 @@ function db_query($query) { function db_close() { global $db, $db_settings; - $db->query("DROP DATABASE `{$db_settings['database']}`"); $db->close(); } From 8c128a80aa6625da31854a6d742b3d1082e8cb22 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 17:32:25 +0100 Subject: [PATCH 42/75] Run tests both with and without cache --- tests/DatabaseTestCase.php | 8 ++++++-- tests/README.md | 2 +- tests/no_cache.php | 6 ++++++ tests/phpunit.xml | 17 +++++++++-------- tests/tests.sh | 14 ++++++++++++++ tests/with_cache.php | 6 ++++++ 6 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 tests/no_cache.php create mode 100755 tests/tests.sh create mode 100644 tests/with_cache.php diff --git a/tests/DatabaseTestCase.php b/tests/DatabaseTestCase.php index aac81b8..c02ef8e 100644 --- a/tests/DatabaseTestCase.php +++ b/tests/DatabaseTestCase.php @@ -4,10 +4,14 @@ class DatabaseTestCase extends PHPUnit_Framework_TestCase { protected $backupGlobalsBlacklist = array('db'); public static function setUpBeforeClass() { + global $cache; db_init(); BasicObject::enable_structure_cache(MC::get_instance()); - //make sure cache is only on when explicitly set - BasicObject::disable_cache(); + if($cache) { + BasicObject::enable_cache(); + } else { + BasicObject::disable_cache(); + } } public function setUp() { diff --git a/tests/README.md b/tests/README.md index dc0fec3..813ab13 100644 --- a/tests/README.md +++ b/tests/README.md @@ -3,7 +3,7 @@ Tests To run the tests: - phpunit + ./tests.sh To create new tests, add files to suites/ (see exists tests for examples), and optionally edit phpunit.xml if you create a new suite diff --git a/tests/no_cache.php b/tests/no_cache.php new file mode 100644 index 0000000..4155831 --- /dev/null +++ b/tests/no_cache.php @@ -0,0 +1,6 @@ + + - - - suites/BasicObject/BasicTest.php - + + + suites/BasicObject/BasicTest.php + - + diff --git a/tests/tests.sh b/tests/tests.sh new file mode 100755 index 0000000..1f20466 --- /dev/null +++ b/tests/tests.sh @@ -0,0 +1,14 @@ +echo "Running tests without cache\n" +phpunit --bootstrap "no_cache.php" + +ret=$? + +if [ $ret -ne 0 ]; then + exit $ret +fi + + +echo "\n----------------------\n" +echo "Running tests with cache\n" +phpunit --bootstrap "with_cache.php" +exit $? diff --git a/tests/with_cache.php b/tests/with_cache.php new file mode 100644 index 0000000..4e5659f --- /dev/null +++ b/tests/with_cache.php @@ -0,0 +1,6 @@ + Date: Mon, 11 Mar 2013 17:35:20 +0100 Subject: [PATCH 43/75] Add more tests --- tests/suites/BasicObject/BasicTest.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/suites/BasicObject/BasicTest.php b/tests/suites/BasicObject/BasicTest.php index 8bd0723..312da3b 100644 --- a/tests/suites/BasicObject/BasicTest.php +++ b/tests/suites/BasicObject/BasicTest.php @@ -52,5 +52,29 @@ public function testArrayInsert() { $this->assertEquals($model1->str1, "Test"); } + /** + * @depends testInsert + */ + public function testIsset() { + $model = Blueprint::make('Model1', false); + $this->assertTrue(isset($model->id), 'id'); + $this->assertTrue(isset($model->int1), 'int1'); + $this->assertTrue(isset($model->str1), 'str1'); + $this->assertFalse(isset($model->foobar)); + } + + /** + * @depends testInsert + */ + public function testDelete() { + $model = Blueprint::make('Model1'); + $id = $model->id; + + $model->delete(); + + $model = Model1::from_id($id); + $this->assertNull($model); + } + } From c61851895b4dc5ca33e2c8d040aab1b8c0c52f2a Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 17:35:26 +0100 Subject: [PATCH 44/75] Fix isset($bo->id) returning false --- BasicObject.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BasicObject.php b/BasicObject.php index 7d0535c..9fe8236 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -322,6 +322,8 @@ protected function is_protected($name) { * @returns bool Returns True if the value exists an is not null, false otherwise. */ public function __isset($name) { + if($name == 'id') return true; + if(isset($this->_data[$name])) { return true; } From e7aabe3fc8d5677eb2b3d8d50e91a446523354a3 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 17:54:41 +0100 Subject: [PATCH 45/75] Add helper for comparing result arrays --- tests/helpers.php | 24 ++++++++++++++++++++++++ tests/includes.php | 1 + 2 files changed, 25 insertions(+) create mode 100644 tests/helpers.php diff --git a/tests/helpers.php b/tests/helpers.php new file mode 100644 index 0000000..72b5f65 --- /dev/null +++ b/tests/helpers.php @@ -0,0 +1,24 @@ + Date: Mon, 11 Mar 2013 17:55:01 +0100 Subject: [PATCH 46/75] Add more Basic tests --- tests/suites/BasicObject/BasicTest.php | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/suites/BasicObject/BasicTest.php b/tests/suites/BasicObject/BasicTest.php index 312da3b..44fcd08 100644 --- a/tests/suites/BasicObject/BasicTest.php +++ b/tests/suites/BasicObject/BasicTest.php @@ -76,5 +76,33 @@ public function testDelete() { $this->assertNull($model); } + /** + * @depends testInsert + */ + public function testSelection() { + $key = 'selection_test'; + $models = array( + Blueprint::make('Model1', array('str1' => $key)), + Blueprint::make('Model1', array('str1' => $key)), + ); + $res = Model1::selection(array('str1' => $key)); + $this->assertCount(count($models), $res); + + $this->assertTrue(compare_result($res, $models)); + } + + /** + * @depends testSelection + */ + public function testSum() { + $sum = 0; + $key = "sumtest"; + for($i = 0; $i < 100; ++$i) { + Blueprint::make('Model1', array('str1' => $key, 'int1' => $i)); + $sum += $i; + } + $this->assertEquals(Model1::sum('int1', array('str1' => $key)), $sum); + } + } From 3f6959e54e5f258566ac96f8c8d427071ec86c12 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 18:46:31 +0100 Subject: [PATCH 47/75] Add vim swapfiles to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d91585e..e69d7b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ tests/settings.php +*.swp From 5d399c2befd00cc618f46c4a97e9e532450acabf Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 18:46:53 +0100 Subject: [PATCH 48/75] Add more tests --- tests/models/Model1Ordered.php | 14 ++++ tests/phpunit.xml | 7 ++ tests/suites/BasicObject/BasicTest.php | 11 +++ tests/suites/BasicObject/RelationsTest.php | 12 ++++ tests/suites/BasicObject/SelectionTest.php | 41 +++++++++++ .../BasicObject/SimpleFunctionsTest.php | 68 +++++++++++++++++++ 6 files changed, 153 insertions(+) create mode 100644 tests/models/Model1Ordered.php create mode 100644 tests/suites/BasicObject/RelationsTest.php create mode 100644 tests/suites/BasicObject/SelectionTest.php create mode 100644 tests/suites/BasicObject/SimpleFunctionsTest.php diff --git a/tests/models/Model1Ordered.php b/tests/models/Model1Ordered.php new file mode 100644 index 0000000..fbbdb66 --- /dev/null +++ b/tests/models/Model1Ordered.php @@ -0,0 +1,14 @@ + suites/BasicObject/BasicTest.php + suites/BasicObject/SelectionTest.php + + + + suites/BasicObject + suites/BasicObject/BasicTest.php + suites/BasicObject/SelectionTest.php diff --git a/tests/suites/BasicObject/BasicTest.php b/tests/suites/BasicObject/BasicTest.php index 44fcd08..df30e25 100644 --- a/tests/suites/BasicObject/BasicTest.php +++ b/tests/suites/BasicObject/BasicTest.php @@ -104,5 +104,16 @@ public function testSum() { $this->assertEquals(Model1::sum('int1', array('str1' => $key)), $sum); } + /** + * @depends testSelection + */ + public function testCount() { + $key = "counttest"; + for($i = 0; $i < 50; ++$i) { + Blueprint::make('Model1', array('str1' => $key)); + } + $this->assertEquals(Model1::count(array('str1' => $key)), 50); + } + } diff --git a/tests/suites/BasicObject/RelationsTest.php b/tests/suites/BasicObject/RelationsTest.php new file mode 100644 index 0000000..5e6f1a7 --- /dev/null +++ b/tests/suites/BasicObject/RelationsTest.php @@ -0,0 +1,12 @@ + 1, 'str1' => $key)); + $m2 = Blueprint::make('Model1', array('int1' => 2, 'str1' => $key)); + + $selection = Model1::selection(array('str1' => $key, '@order' => 'int1')); + $this->assertEquals($selection[0]->id, $m1->id); + $this->assertEquals($selection[1]->id, $m2->id); + + $selection = Model1::selection(array('str1' => $key, '@order' => 'int1:desc')); + $this->assertEquals($selection[0]->id, $m2->id); + $this->assertEquals($selection[1]->id, $m1->id); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage No such column 'foobar' in table 'model1' (value 'bar') + */ + public function testUnknowColumn() { + Model1::selection(array('foobar' => 'bar')); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage No such table 'foobar' + */ + public function testInvalidJoin() { + Model1::selection(array('foobar.foo' => 'a')); + } + + /* TODO: Add much more tests */ +} diff --git a/tests/suites/BasicObject/SimpleFunctionsTest.php b/tests/suites/BasicObject/SimpleFunctionsTest.php new file mode 100644 index 0000000..964680b --- /dev/null +++ b/tests/suites/BasicObject/SimpleFunctionsTest.php @@ -0,0 +1,68 @@ + 1, 'str1' => 'firsttest')); + $m2 = Blueprint::make('Model1', array('int1' => 2, 'str1' => 'firsttest')); + + $this->assertEquals(Model1::first(array('str1' => 'firsttest', '@order' => 'int1'))->id, $m1->id); + $this->assertEquals(Model1::first(array('str1' => 'firsttest', '@order' => 'int1:desc'))->id, $m2->id); + } + + public function testOne() { + $m1 = Blueprint::make('Model1'); + + $obj = Model1::one(array('int1' => $m1->int1)); + + $this->assertEquals($obj->id, $m1->id); + } + + /** + * @expectedException Exception + */ + public function testOneFailsCorrectly() { + $m1 = Blueprint::make('Model1', array('str1' => 'testonefail')); + $m1 = Blueprint::make('Model1', array('str1' => 'testonefail')); + + Model1::one(array('str1' => 'testonefail')); + } + + public function testDuplicate() { + $m1 = Blueprint::make('Model1'); + $m2 = $m1->duplicate(); + + $this->assertNull($m2->id); + $this->assertEquals($m2->int1, $m1->int1); + $this->assertEquals($m2->str1, $m1->str1); + + $m2->int1++; + $this->assertEquals($m1->int1 + 1, $m2->int1); + + $m2->commit(); + + $this->assertNotNull($m2->id); + + $this->assertNotEquals($m1->id, $m2->id); + } + + public function testOutputHTMLSpecialChars() { + + } + + public function testDefaultOrder() { + $key = "ordertest"; + $m1 = Blueprint::make('Model1', array('int1' => 1, 'str1' => $key)); + $m2 = Blueprint::make('Model1', array('int1' => 2, 'str1' => $key)); + + Model1Ordered::$order = "int1"; + $selection = Model1Ordered::selection(array('str1' => $key)); + $this->assertEquals($selection[0]->id, $m1->id); + $this->assertEquals($selection[1]->id, $m2->id); + + Model1Ordered::$order = "int1:desc"; + $selection = Model1Ordered::selection(array('str1' => $key)); + $this->assertEquals($selection[0]->id, $m2->id); + $this->assertEquals($selection[1]->id, $m1->id); + } + +} From 53fcfc01d80dd762b722f0718e46117ed360d5bd Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 18:47:03 +0100 Subject: [PATCH 49/75] Handle default_order same as @order --- BasicObject.php | 53 ++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 9fe8236..e60dd61 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -788,7 +788,7 @@ private static function build_query($params, $select){ if(count($order) == 0 && strpos(strtolower($wheres),'order by') === false) { // Set default order if(static::default_order() != null) - $order[] = static::default_order(); + self::handle_order(static::default_order(), $joins, $order, $table_name, self::columns($table_name)); } $query = "SELECT "; @@ -854,28 +854,7 @@ private static function handle_params($params, &$joins, &$wheres, &$order, &$tab $order[] = $value; break; case '@order': - if(!is_array($value)){ - $value = array($value); - } - foreach($value as $o){ - $desc = false; - if(substr($o,-5) == ':desc'){ - $desc = true; - $o = substr($o, 0,-5); - } - $path = explode('.', $o); - if(count($path)>1){ - $o = '`'.self::fix_join($path, $joins, $columns, $table_name).'`'; - } elseif(self::in_table($o, $table_name)){ - $o = "`$table_name`.`$o`"; - } else { - throw new Exception("No such column '$o' in table '$table_name' (value '$value')"); - } - if($desc){ - $o .= ' DESC'; - } - $order[] = $o; - } + self::handle_order($value, $joins, $order, $table_name, $columns); break; case '@limit': if(is_numeric($value)){ @@ -1289,6 +1268,34 @@ private static function get_database_name() { return $db_name; } + /** + * Helper method for handling @order and default_order + */ + private static function handle_order($value,&$joins, &$order, &$table_name, &$columns) { + if(!is_array($value)){ + $value = array($value); + } + foreach($value as $o){ + $desc = false; + if(substr($o,-5) == ':desc'){ + $desc = true; + $o = substr($o, 0,-5); + } + $path = explode('.', $o); + if(count($path)>1){ + $o = '`'.self::fix_join($path, $joins, $columns, $table_name).'`'; + } elseif(self::in_table($o, $table_name)){ + $o = "`$table_name`.`$o`"; + } else { + throw new Exception("No such column '$o' in table '$table_name' (value '$value')"); + } + if($desc){ + $o .= ' DESC'; + } + $order[] = $o; + } + } + public function __toString() { $content = array(); foreach(self::columns($this->table_name()) as $c) { From 192def661baa17b4a0ee21ec82bb4efb8f228e42 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 18:51:39 +0100 Subject: [PATCH 50/75] Add test for relation options --- tests/suites/BasicObject/RelationsTest.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/suites/BasicObject/RelationsTest.php b/tests/suites/BasicObject/RelationsTest.php index 5e6f1a7..178bb5a 100644 --- a/tests/suites/BasicObject/RelationsTest.php +++ b/tests/suites/BasicObject/RelationsTest.php @@ -3,10 +3,27 @@ class RelationTest extends DatabaseTestCase { public function testGetOtherModel() { - + $m1 = Blueprint::make('Model1'); + $m2 = Blueprint::make('Model2'); + $m1->model2_id = $m2->id; + $m1->commit(); + + $m2_ret = $m1->Model2(); + $this->assertEquals($m2, $m2_ret); } + /** + * @depends testGetOtherModel + */ public function testSetOtherModel() { + $m1 = Blueprint::make('Model1'); + $m2 = Blueprint::make('Model2'); + + $m1->Model2 = $m2; + + $this->assertEquals($m2->id, $m1->model2_id); + $this->assertEquals($m2, $m1->Model2()); + $m1->commit(); } } From ceb29cb25f49356bba9b7442df2d4da53ec8fb64 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 19:05:00 +0100 Subject: [PATCH 51/75] Handle setting of other BO instance correctly --- BasicObject.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index e60dd61..fc338a2 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -362,8 +362,18 @@ public function __set($name, $value) { $this->_old_key[$name] = $this->$name; } $this->_data[$name] = $value; - } elseif($this->is_table($name) && $this->in_table($this->id_name($name), $this->table_name())) { - $name = $this->id_name($name); + } elseif($this->is_table($name)) { + $connection = self::connection($name, $this->table_name()); + if($connection && $connection['TABLE_NAME'] == $this->table_name()) { + $name = $connection['COLUMN_NAME']; + } else { + $other_id = self::id_name($name); + if($other_id != 'id' && in_array($other_id, self::columns($this->table_name()))) { + $name = $other_id; + } else { + throw new Exception("No connection from '{$this->table_name()}' to table '$name'"); + } + } $this->$name = $value->id; } else { throw new Exception("unknown property '$name'"); From bd3128ed51d8ae51a3ebb1207e79aaa08ab560cb Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 19:12:53 +0100 Subject: [PATCH 52/75] More tests --- tests/suites/BasicObject/SimpleFunctionsTest.php | 13 +++++++++++++ tests/tests.sh | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/suites/BasicObject/SimpleFunctionsTest.php b/tests/suites/BasicObject/SimpleFunctionsTest.php index 964680b..9bd51a5 100644 --- a/tests/suites/BasicObject/SimpleFunctionsTest.php +++ b/tests/suites/BasicObject/SimpleFunctionsTest.php @@ -46,7 +46,20 @@ public function testDuplicate() { } public function testOutputHTMLSpecialChars() { + $html = "Foobar \" "; + $m1 = Blueprint::make('Model1', array('str1' => $html)); + BasicObject::$output_htmlspecialchars = false; + + $m1 = Model1::from_id($m1->id); + + $this->assertEquals($html, $m1->str1); + + BasicObject::$output_htmlspecialchars = true; + $escaped = htmlspecialchars($html, ENT_QUOTES, 'utf-8'); + $this->assertEquals($escaped, $m1->str1); + + BasicObject::$output_htmlspecialchars = false; } public function testDefaultOrder() { diff --git a/tests/tests.sh b/tests/tests.sh index 1f20466..fbfc335 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -1,5 +1,5 @@ echo "Running tests without cache\n" -phpunit --bootstrap "no_cache.php" +phpunit --bootstrap "no_cache.php" --verbose $@ ret=$? @@ -10,5 +10,5 @@ fi echo "\n----------------------\n" echo "Running tests with cache\n" -phpunit --bootstrap "with_cache.php" +phpunit --bootstrap "with_cache.php" --verbose $@ exit $? From da91882ca6ced1a154b07da97ccb5fceec29f9c0 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 19:23:50 +0100 Subject: [PATCH 53/75] Add structure for cache tests --- tests/suites/BasicObject/CacheTest.php | 22 ++++++++++++++++++++++ tests/tests.sh | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/suites/BasicObject/CacheTest.php diff --git a/tests/suites/BasicObject/CacheTest.php b/tests/suites/BasicObject/CacheTest.php new file mode 100644 index 0000000..ae19813 --- /dev/null +++ b/tests/suites/BasicObject/CacheTest.php @@ -0,0 +1,22 @@ + Date: Mon, 11 Mar 2013 19:26:27 +0100 Subject: [PATCH 54/75] Add test for commit invalidating cache --- tests/suites/BasicObject/CacheTest.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/suites/BasicObject/CacheTest.php b/tests/suites/BasicObject/CacheTest.php index ae19813..9512d8d 100644 --- a/tests/suites/BasicObject/CacheTest.php +++ b/tests/suites/BasicObject/CacheTest.php @@ -17,6 +17,15 @@ public function assertPreConditions() { } } - public function testFromField() { + public function testEditAndLoad() { + $m1 = Blueprint::make('Model1'); + $m1 = Model1::from_id($m1->id); + $val = $m1->int1 + 10; + $m1->int1 = $val; + $m1->commit(); + + $m1 = Model1::from_id($m1->id); + $this->assertEquals($val, $m1->int1); + } } From eb0344b0e2c6f03f3e59933ead09b083307392dd Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 19:30:51 +0100 Subject: [PATCH 55/75] Change order of arguments to assertEquals The correct order is expected, real --- tests/suites/BasicObject/BasicTest.php | 16 ++++++++-------- tests/suites/BasicObject/SelectionTest.php | 8 ++++---- .../suites/BasicObject/SimpleFunctionsTest.php | 18 +++++++++--------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/suites/BasicObject/BasicTest.php b/tests/suites/BasicObject/BasicTest.php index df30e25..2b3dc25 100644 --- a/tests/suites/BasicObject/BasicTest.php +++ b/tests/suites/BasicObject/BasicTest.php @@ -10,8 +10,8 @@ public function testFromId() { $id = $db->insert_id; $obj = Model1::from_id($id); $this->assertNotNull($obj); - $this->assertEquals($obj->int1, 5); - $this->assertEquals($obj->str1, "foobar"); + $this->assertEquals(5, $obj->int1); + $this->assertEquals("foobar", $obj->str1); } /** @@ -30,8 +30,8 @@ public function testInsert() { $model1 = Model1::from_id($id); - $this->assertEquals($model1->int1, 1); - $this->assertEquals($model1->str1, "Test"); + $this->assertEquals(1, $model1->int1); + $this->assertEquals("Test", $model1->str1); } /** @@ -48,8 +48,8 @@ public function testArrayInsert() { $model1 = Model1::from_id($id); - $this->assertEquals($model1->int1, 1); - $this->assertEquals($model1->str1, "Test"); + $this->assertEquals(1, $model1->int1); + $this->assertEquals("Test", $model1->str1); } /** @@ -101,7 +101,7 @@ public function testSum() { Blueprint::make('Model1', array('str1' => $key, 'int1' => $i)); $sum += $i; } - $this->assertEquals(Model1::sum('int1', array('str1' => $key)), $sum); + $this->assertEquals($sum, Model1::sum('int1', array('str1' => $key))); } /** @@ -112,7 +112,7 @@ public function testCount() { for($i = 0; $i < 50; ++$i) { Blueprint::make('Model1', array('str1' => $key)); } - $this->assertEquals(Model1::count(array('str1' => $key)), 50); + $this->assertEquals(50, Model1::count(array('str1' => $key))); } } diff --git a/tests/suites/BasicObject/SelectionTest.php b/tests/suites/BasicObject/SelectionTest.php index 3b12108..c7c50c1 100644 --- a/tests/suites/BasicObject/SelectionTest.php +++ b/tests/suites/BasicObject/SelectionTest.php @@ -13,12 +13,12 @@ public function testOrder() { $m2 = Blueprint::make('Model1', array('int1' => 2, 'str1' => $key)); $selection = Model1::selection(array('str1' => $key, '@order' => 'int1')); - $this->assertEquals($selection[0]->id, $m1->id); - $this->assertEquals($selection[1]->id, $m2->id); + $this->assertEquals($m1->id, $selection[0]->id); + $this->assertEquals($m2->id, $selection[1]->id); $selection = Model1::selection(array('str1' => $key, '@order' => 'int1:desc')); - $this->assertEquals($selection[0]->id, $m2->id); - $this->assertEquals($selection[1]->id, $m1->id); + $this->assertEquals($m2->id, $selection[0]->id); + $this->assertEquals($m1->id, $selection[1]->id); } /** diff --git a/tests/suites/BasicObject/SimpleFunctionsTest.php b/tests/suites/BasicObject/SimpleFunctionsTest.php index 9bd51a5..f93a562 100644 --- a/tests/suites/BasicObject/SimpleFunctionsTest.php +++ b/tests/suites/BasicObject/SimpleFunctionsTest.php @@ -5,8 +5,8 @@ public function testFirst() { $m1 = Blueprint::make('Model1', array('int1' => 1, 'str1' => 'firsttest')); $m2 = Blueprint::make('Model1', array('int1' => 2, 'str1' => 'firsttest')); - $this->assertEquals(Model1::first(array('str1' => 'firsttest', '@order' => 'int1'))->id, $m1->id); - $this->assertEquals(Model1::first(array('str1' => 'firsttest', '@order' => 'int1:desc'))->id, $m2->id); + $this->assertEquals($m1->id, Model1::first(array('str1' => 'firsttest', '@order' => 'int1'))->id); + $this->assertEquals($m2->id, Model1::first(array('str1' => 'firsttest', '@order' => 'int1:desc'))->id); } public function testOne() { @@ -14,7 +14,7 @@ public function testOne() { $obj = Model1::one(array('int1' => $m1->int1)); - $this->assertEquals($obj->id, $m1->id); + $this->assertEquals($m1->id, $obj->id); } /** @@ -32,8 +32,8 @@ public function testDuplicate() { $m2 = $m1->duplicate(); $this->assertNull($m2->id); - $this->assertEquals($m2->int1, $m1->int1); - $this->assertEquals($m2->str1, $m1->str1); + $this->assertEquals($m1->int1, $m2->int1); + $this->assertEquals($m1->str1, $m2->str1); $m2->int1++; $this->assertEquals($m1->int1 + 1, $m2->int1); @@ -69,13 +69,13 @@ public function testDefaultOrder() { Model1Ordered::$order = "int1"; $selection = Model1Ordered::selection(array('str1' => $key)); - $this->assertEquals($selection[0]->id, $m1->id); - $this->assertEquals($selection[1]->id, $m2->id); + $this->assertEquals($m1->id, $selection[0]->id); + $this->assertEquals($m2->id, $selection[1]->id); Model1Ordered::$order = "int1:desc"; $selection = Model1Ordered::selection(array('str1' => $key)); - $this->assertEquals($selection[0]->id, $m2->id); - $this->assertEquals($selection[1]->id, $m1->id); + $this->assertEquals($m2->id, $selection[0]->id); + $this->assertEquals($m1->id, $selection[1]->id); } } From e233223e4fa4f3b2bb8c0290a2cae39e514b3005 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 19:43:21 +0100 Subject: [PATCH 56/75] Add database wrapper with query counter --- tests/database.php | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/database.php b/tests/database.php index caac56f..59b1a88 100644 --- a/tests/database.php +++ b/tests/database.php @@ -8,7 +8,7 @@ function db_init() { global $db, $db_settings; /* Database */ - $db = new mysqli( + $db = new CountingDB( $db_settings['host'], $db_settings['username'], $db_settings['password'], @@ -56,3 +56,31 @@ function db_close() { global $db, $db_settings; $db->close(); } + +/** + * Counting database class + */ + +class CountingDB extends MySQLi { + + public static $queries = 0; + + public function __construct($host, $username, $password, $database, $port) { + parent::__construct($host, $username, $password, $database, $port); + } + + public function prepare($query) { + return new CountingStatement($this, $query); + } +} + +class CountingStatement extends mysqli_stmt { + public function __construct($db, $query) { + parent::__construct($db, $query); + } + + public function execute() { + ++CountingDB::$queries; + return parent::execute(); + } +} From 831dd151461768b754494f39f20297f5a2bdd2d1 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 19:43:32 +0100 Subject: [PATCH 57/75] Add query reduction test --- tests/suites/BasicObject/CacheTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/suites/BasicObject/CacheTest.php b/tests/suites/BasicObject/CacheTest.php index 9512d8d..a0048b9 100644 --- a/tests/suites/BasicObject/CacheTest.php +++ b/tests/suites/BasicObject/CacheTest.php @@ -26,6 +26,21 @@ public function testEditAndLoad() { $m1 = Model1::from_id($m1->id); $this->assertEquals($val, $m1->int1); + } + + public function testQueryReductionFromId() { + CountingDB::$queries = 0; + + $m1 = Blueprint::make('Model1'); + $id = $m1->id; + + Model1::from_id($id); + $num_queries = CountingDB::$queries; + for($i=0; $i<100; ++$i) { + $m = Model1::from_id($id); + $this->assertEquals($m1, $m); + } + $this->assertEquals($num_queries, CountingDB::$queries); } } From 3426fde8f7c60b66771ccfc286f008990cbc79fb Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 19:50:30 +0100 Subject: [PATCH 58/75] Dont stop on failure --- tests/phpunit.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 158e05e..4e6407e 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -1,6 +1,5 @@ From 82c47861355d088886f153f55b9131d826f64ada Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 19:50:37 +0100 Subject: [PATCH 59/75] Add more query reduction tests --- tests/suites/BasicObject/CacheTest.php | 45 ++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/suites/BasicObject/CacheTest.php b/tests/suites/BasicObject/CacheTest.php index a0048b9..792f341 100644 --- a/tests/suites/BasicObject/CacheTest.php +++ b/tests/suites/BasicObject/CacheTest.php @@ -37,8 +37,49 @@ public function testQueryReductionFromId() { Model1::from_id($id); $num_queries = CountingDB::$queries; for($i=0; $i<100; ++$i) { - $m = Model1::from_id($id); - $this->assertEquals($m1, $m); + Model1::from_id($id); + } + + $this->assertEquals($num_queries, CountingDB::$queries); + } + + public function testQueryReductionSelection() { + CountingDB::$queries = 0; + + $m1 = Blueprint::make('Model1'); + + Model1::selection(array('int1' => $m1->int1)); + $num_queries = CountingDB::$queries; + for($i=0; $i<100; ++$i) { + Model1::selection(array('int1' => $m1->int1)); + } + + $this->assertEquals($num_queries, CountingDB::$queries); + } + + public function testQueryReductionCount() { + CountingDB::$queries = 0; + + $m1 = Blueprint::make('Model1'); + + Model1::count(array('int1' => $m1->int1)); + $num_queries = CountingDB::$queries; + for($i=0; $i<100; ++$i) { + Model1::count(array('int1' => $m1->int1)); + } + + $this->assertEquals($num_queries, CountingDB::$queries); + } + + public function testQueryReductionSum() { + CountingDB::$queries = 0; + + $m1 = Blueprint::make('Model1'); + + Model1::sum('int1', array('int1' => $m1->int1)); + $num_queries = CountingDB::$queries; + for($i=0; $i<100; ++$i) { + Model1::sum('int1', array('int1' => $m1->int1)); } $this->assertEquals($num_queries, CountingDB::$queries); From 7d1f9c3f2388daf936ca758a2ba178fc5d928b45 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 20:07:08 +0100 Subject: [PATCH 60/75] Implement more tests --- tests/blueprints/Model1.json | 5 +++++ tests/suites/BasicObject/SelectionTest.php | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/tests/blueprints/Model1.json b/tests/blueprints/Model1.json index 5bf274b..11594da 100644 --- a/tests/blueprints/Model1.json +++ b/tests/blueprints/Model1.json @@ -2,5 +2,10 @@ default: { int1: "100#{sn}", str1: "str-#{sn}" + }, + with_model2: { + int1: "100#{sn}", + str1: "str-#{sn}", + Model2: {} } } diff --git a/tests/suites/BasicObject/SelectionTest.php b/tests/suites/BasicObject/SelectionTest.php index c7c50c1..06cc57c 100644 --- a/tests/suites/BasicObject/SelectionTest.php +++ b/tests/suites/BasicObject/SelectionTest.php @@ -2,9 +2,20 @@ class SelectionTest extends DatabaseTestCase { public function testAutomaticJoin() { + $m1 = Blueprint::make('Model1', "with_model2"); + + $m1_ref = Model1::selection(array('model2.int1' => $m1->Model2()->int1)); + $this->assertCount(1, $m1_ref); + $this->assertEquals($m1, $m1_ref[0]); } public function testManualJoin() { + $m1 = Blueprint::make('Model1', array('int1' => 5000)); + $m2 = Blueprint::make('Model2', array('int1' => 5000, 'str1' => 'derp')); + + $m1_ref = Model1::selection(array( '@join' => array( 'model2:using' => 'int1')) ); + $this->assertCount(1, $m1_ref); + $this->assertEquals($m1, $m1_ref[0]); } public function testOrder() { From 4e3a3a621ca03e8209000e4d3f9bf105d2709044 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Mon, 11 Mar 2013 20:21:53 +0100 Subject: [PATCH 61/75] Fail if settings.php don't exists --- tests/database.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/database.php b/tests/database.php index 59b1a88..ea16b50 100644 --- a/tests/database.php +++ b/tests/database.php @@ -1,6 +1,15 @@ Date: Mon, 11 Mar 2013 21:12:24 +0100 Subject: [PATCH 62/75] Enable strict --- tests/database.php | 2 +- tests/includes.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/database.php b/tests/database.php index ea16b50..c261228 100644 --- a/tests/database.php +++ b/tests/database.php @@ -51,7 +51,7 @@ function db_run_file($filename) { do { $result = $db->use_result(); if($result) $result->free(); - } while($db->next_result()); + } while($db->more_results() && $db->next_result()); } function db_query($query) { diff --git a/tests/includes.php b/tests/includes.php index ec51501..9c20964 100644 --- a/tests/includes.php +++ b/tests/includes.php @@ -1,5 +1,7 @@ Date: Mon, 11 Mar 2013 21:13:27 +0100 Subject: [PATCH 63/75] Don't pass columns to handle_order by ref --- BasicObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BasicObject.php b/BasicObject.php index 69ca2ab..d607376 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -1286,7 +1286,7 @@ private static function get_database_name() { /** * Helper method for handling @order and default_order */ - private static function handle_order($value,&$joins, &$order, &$table_name, &$columns) { + private static function handle_order($value,&$joins, &$order, &$table_name, $columns) { if(!is_array($value)){ $value = array($value); } From 22c6aff45dc6a779d1da76bea06872f484e087e6 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Tue, 12 Mar 2013 00:21:09 +0100 Subject: [PATCH 64/75] Clear structure cache variables when flushing cache --- BasicObject.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BasicObject.php b/BasicObject.php index d607376..763a7b5 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -151,6 +151,10 @@ public static function enable_structure_cache($memcache) { public static function clear_structure_cache($memcache) { $memcache->flush(); + BasicObject::$column_ids = array(); + BasicObject::$connection_table = array(); + BasicObject::$tables = null; + BasicObject::$columns = array(); } private static function store_column_ids() { From f11ff965324abcae6d38616c66f5a409e2d6bd01 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Thu, 21 Mar 2013 22:21:01 +0100 Subject: [PATCH 65/75] min,max shortcuts for validate_length_of --- ValidatingBasicObject.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ValidatingBasicObject.php b/ValidatingBasicObject.php index cf4cfed..bd2dd54 100644 --- a/ValidatingBasicObject.php +++ b/ValidatingBasicObject.php @@ -168,6 +168,9 @@ protected function validate_numericality_of($var,$options=array()) { protected function validate_length_of($var,$options=array()) { $len = strlen($this->$var); + if ( isset($options['min']) ) $options['minimum'] = $options['min']; + if ( isset($options['max']) ) $options['maximum'] = $options['max']; + if(isset($options['is']) && $len != $options['is']) { $message = "måste vara exakt {$options['is']} tecken lång"; $this->add_error($var,isset($options['message'])?$options['message']:$message); From 48be1d9bca59d8bb8506fb269ca18c4268c98103 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Fri, 22 Mar 2013 00:36:07 +0100 Subject: [PATCH 66/75] Allow optional selection arguments to join __call Eg. $foo->Bar(array('baz' => 'bar')) --- BasicObject.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/BasicObject.php b/BasicObject.php index 763a7b5..ec66d35 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -265,6 +265,9 @@ public function __call($name, $arguments){ } else { // They know us (multiple values) $params[$con['COLUMN_NAME']] = $this->id; + if(count($arguments) == 1 && is_array($arguments[0])) { + $params = array_merge($arguments[0], $params); + } return $name::selection($params); } } From 0203ce411ef304b49b82183b6256ef2c7ae1b1fb Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Fri, 22 Mar 2013 14:35:11 +0100 Subject: [PATCH 67/75] Add clarifying comment --- BasicObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BasicObject.php b/BasicObject.php index ec66d35..4f1c71e 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -734,7 +734,7 @@ public static function count($params = array(), $debug = false){ * * Joins: <>: The join type (eg. LEFT,RIGHT OUTER etc) * This produces the join " <> JOIN <
> <> <> - * Operator can be 'on' or 'using' + * Operator can be 'on' or 'using' (default 'on') * * @returns Array An array of Objects. */ From 09720f8c3f7270d4562fdbaf990a6932139c0af2 Mon Sep 17 00:00:00 2001 From: Petter Blomberg Date: Tue, 4 Jun 2013 17:12:13 +0200 Subject: [PATCH 68/75] Undo exception for bad column names Undo of commit e8c7537514d1432cd154ac35363d97c2d33cdde4 "Invalid" names after : in column names should be accepted, so that one can construct several where clauses on the same column. --- BasicObject.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 543087d..879f2f7 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -579,9 +579,6 @@ private static function handle_params($params, &$joins, &$wheres, &$order, &$tab } if($column[0] == '@'){ $column = explode(':', $column); - if(count($column)>1) { - throw new Exception("Invalid column"); - } $column = $column[0]; // special parameter switch($column){ From 58c6d85b1e3c7ab1bc0e5e06fe68818a2466398b Mon Sep 17 00:00:00 2001 From: Petter Blomberg Date: Wed, 5 Jun 2013 14:09:16 +0200 Subject: [PATCH 69/75] clear_structure_cache fix: don't flush everything After this patch, it only deletes the keys used for structure cache. This is important, because I have other caches in memcache that I want to keep, even when I run migrations that alter db structure. --- BasicObject.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BasicObject.php b/BasicObject.php index 4f1c71e..4b6517b 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -150,7 +150,10 @@ public static function enable_structure_cache($memcache) { } public static function clear_structure_cache($memcache) { - $memcache->flush(); + $memcache->delete("column_ids"); + $memcache->delete("connection_table"); + $memcache->delete("tables"); + $memcache->delete("columns"); BasicObject::$column_ids = array(); BasicObject::$connection_table = array(); BasicObject::$tables = null; From d699016c7a96ef62b1e1116c9509074e2f1a062d Mon Sep 17 00:00:00 2001 From: Petter Blomberg Date: Wed, 5 Jun 2013 14:30:46 +0200 Subject: [PATCH 70/75] Fix comment --- BasicObject.php | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 4b6517b..127b1ee 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -9,12 +9,21 @@ abstract class BasicObject { protected $_old_key = array(); protected $_exists; - /* - * [ - * 'table:field' => [ - * value => object - * ] - * ] + /* Cache of objects returned from FooObject::from_field() + * var_dump of $_from_field_cache would output something like: + * array(x) { + * ["table1:field1"]=> + * array(x) { + * ["value"]=> + * object(FooObject)#X (x) { + * ... object properties ... + * } + * } + * ["table1:field2"]=> + * array(x) { + * ... + * } + * } */ protected static $_from_field_cache = array(); @@ -39,7 +48,7 @@ abstract class BasicObject { public static $output_htmlspecialchars; - /* + /** * Methods for toggling query caching on and off * Default: Off */ From e94ac5d48780e528efd1f88ceea1c404010188dc Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Wed, 5 Jun 2013 15:09:45 +0200 Subject: [PATCH 71/75] Text about tests in readme And a script to install phpunit --- README.md | 6 ++++++ tests/README.md | 8 ++++++++ tests/install_phpunit.sh | 3 +++ 3 files changed, 17 insertions(+) create mode 100755 tests/install_phpunit.sh diff --git a/README.md b/README.md index 6701b39..36375a0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ BasicObject ========== +Tests +--------- +Run tests before you do a pull requests, and add tests for new features. + +See tests/README.md + Dependencies (Only for running tests) -------------------- diff --git a/tests/README.md b/tests/README.md index 813ab13..e94513d 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,3 +1,11 @@ +PHPUnit +====== + +The tests requires phpunit: https://github.com/sebastianbergmann/phpunit/ +Install it by running + + sudo ./install_phpunit.sh + Tests ===== diff --git a/tests/install_phpunit.sh b/tests/install_phpunit.sh new file mode 100755 index 0000000..6af0ab5 --- /dev/null +++ b/tests/install_phpunit.sh @@ -0,0 +1,3 @@ +#/bin/sh +pear config-set auto_discover 1 +pear install pear.phpunit.de/PHPUnit From 1d564d2d1f13d0b1e80146ca9d541145b23b0ef1 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Sun, 14 Jul 2013 14:25:19 +0200 Subject: [PATCH 72/75] Add validates_uniqueness_of --- ValidatingBasicObject.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ValidatingBasicObject.php b/ValidatingBasicObject.php index bd2dd54..134490c 100644 --- a/ValidatingBasicObject.php +++ b/ValidatingBasicObject.php @@ -256,6 +256,16 @@ protected function validate_equal_to($var,$val,$options=array()) { $this->add_error($var,isset($options['message'])?$options['message']:$message); } } + + /** + * Validates that $var is unique + */ + protected function validate_uniqueness_of($var,$options=array()) { + if(static::count(array($var => $this->$var, '@limit' => 1)) != 0) { + $message = "måste vara unik"; + $this->add_error($var,isset($options['message'])?$options['message']:$message); + } + } } /** From 5f0ccf569273dbdf89a5cd17cb7d3d1bd729df65 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Sun, 14 Jul 2013 16:37:53 +0200 Subject: [PATCH 73/75] validate_uniqueness_of should ignore self --- BasicObject.php | 2 +- ValidatingBasicObject.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 127b1ee..6c77fb0 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -89,7 +89,7 @@ public static function with_tmp_htmlspecialchars($tmp_value, $callback) { * Returns the table name associated with this class. * @return The name of the table this class is associated with. */ - private static function id_name($class_name = null){ + protected static function id_name($class_name = null){ $pk = static::primary_key($class_name); if(count($pk) < 1) { return null; diff --git a/ValidatingBasicObject.php b/ValidatingBasicObject.php index 134490c..0e86582 100644 --- a/ValidatingBasicObject.php +++ b/ValidatingBasicObject.php @@ -261,7 +261,11 @@ protected function validate_equal_to($var,$val,$options=array()) { * Validates that $var is unique */ protected function validate_uniqueness_of($var,$options=array()) { - if(static::count(array($var => $this->$var, '@limit' => 1)) != 0) { + $sel = array($var => $this->$var, '@limit' => 1); + if($this->_exists) { + $sel[static::id_name().":!="] = $this->id; + } + if(static::count($sel) != 0) { $message = "måste vara unik"; $this->add_error($var,isset($options['message'])?$options['message']:$message); } From e0950071cc05cf5de0b5437ecbef40e36ed7a8fc Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Sun, 8 Sep 2013 18:51:35 +0200 Subject: [PATCH 74/75] Add some structure cache tests --- tests/suites/BasicObject/CacheTest.php | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/suites/BasicObject/CacheTest.php b/tests/suites/BasicObject/CacheTest.php index 792f341..29a6526 100644 --- a/tests/suites/BasicObject/CacheTest.php +++ b/tests/suites/BasicObject/CacheTest.php @@ -84,4 +84,57 @@ public function testQueryReductionSum() { $this->assertEquals($num_queries, CountingDB::$queries); } + + public function testStructureCacheFill() { + $sc_vars = $this->getStructureCacheVariables(); + + Model1::from_id(1); + Model1::selection(array('model2.int1' => 1)); + $vals = array(); + foreach($sc_vars as $v => $prop) { + $vals[$v] = $prop->getValue(); + $this->assertNotEmpty($vals[$v]); + } + /*BasicObject::clear_structure_cache(MC::get_instance());*/ + /*BasicObject::*/ + } + + public function testStructureCacheRestore() { + $sc_vars = $this->getStructureCacheVariables(); + + Model1::from_id(1); + Model1::selection(array('model2.int1' => 1)); + $vals = array(); + foreach($sc_vars as $v => $prop) { + $vals[$v] = $prop->getValue(); + $prop->setValue(array()); + } + + BasicObject::enable_structure_cache(MC::get_instance()); + foreach($sc_vars as $v => $prop) { + $this->assertEquals($vals[$v], $prop->getValue()); + } + } + + public function testClearStructureCache() { + $sc_vars = $this->getStructureCacheVariables(); + Model1::from_id(1); + Model1::selection(array('model2.int1' => 1)); + BasicObject::clear_structure_cache(MC::get_instance()); + + BasicObject::enable_structure_cache(MC::get_instance()); + foreach($sc_vars as $v => $prop) { + $this->assertEmpty($prop->getValue()); + } + } + + private function getStructureCacheVariables() { + $ret = array(); + $vars = array('column_ids', 'connection_table', 'tables', 'columns'); + foreach($vars as $var) { + $ret[$var] = new ReflectionProperty('BasicObject', $var); + $ret[$var]->setAccessible(true); + } + return $ret; + } } From 919c044789b6582b780fef7553bf439a5361d026 Mon Sep 17 00:00:00 2001 From: Andreas Tarandi Date: Sun, 8 Sep 2013 19:11:33 +0200 Subject: [PATCH 75/75] Add prefix to structure cache Allows multipe BO on the same memcache --- BasicObject.php | 30 ++++++++++++++------------ tests/DatabaseTestCase.php | 4 ++-- tests/database.php | 2 +- tests/suites/BasicObject/CacheTest.php | 21 +++++++++++++----- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/BasicObject.php b/BasicObject.php index 6c77fb0..9623721 100644 --- a/BasicObject.php +++ b/BasicObject.php @@ -40,6 +40,7 @@ abstract class BasicObject { * Memcache for caching database structure between requests */ private static $memcache = null; + private static $memcache_prefix; private static $column_ids = array(); private static $connection_table = array(); @@ -142,27 +143,28 @@ private static function primary_key($class_name = null) { * Enables structure cache using the provided Memcache object * The memcache instance must be connected */ - public static function enable_structure_cache($memcache) { + public static function enable_structure_cache($memcache, $prefix = "basicobject_") { BasicObject::$memcache = $memcache; + BasicObject::$memcache_prefix = $prefix; - $stored = BasicObject::$memcache->get("column_ids"); + $stored = BasicObject::$memcache->get(BasicObject::$memcache_prefix . "column_ids"); if($stored) BasicObject::$column_ids = unserialize($stored); - $stored = BasicObject::$memcache->get("connection_table"); + $stored = BasicObject::$memcache->get(BasicObject::$memcache_prefix . "connection_table"); if($stored) BasicObject::$connection_table = unserialize($stored); - $stored = BasicObject::$memcache->get("tables"); + $stored = BasicObject::$memcache->get(BasicObject::$memcache_prefix . "tables"); if($stored) BasicObject::$tables = unserialize($stored); - $stored = BasicObject::$memcache->get("columns"); + $stored = BasicObject::$memcache->get(BasicObject::$memcache_prefix . "columns"); if($stored) BasicObject::$columns = unserialize($stored); } - public static function clear_structure_cache($memcache) { - $memcache->delete("column_ids"); - $memcache->delete("connection_table"); - $memcache->delete("tables"); - $memcache->delete("columns"); + public static function clear_structure_cache($memcache, $prefix = "basicobject_") { + $memcache->delete($prefix . "column_ids"); + $memcache->delete($prefix . "connection_table"); + $memcache->delete($prefix . "tables"); + $memcache->delete($prefix . "columns"); BasicObject::$column_ids = array(); BasicObject::$connection_table = array(); BasicObject::$tables = null; @@ -171,25 +173,25 @@ public static function clear_structure_cache($memcache) { private static function store_column_ids() { if(BasicObject::$memcache) { - BasicObject::$memcache->set("column_ids", serialize(BasicObject::$column_ids), 0, 0); /* no expire */ + BasicObject::$memcache->set(BasicObject::$memcache_prefix . "column_ids", serialize(BasicObject::$column_ids), 0, 0); /* no expire */ } } private static function store_connection_table() { if(BasicObject::$memcache) { - BasicObject::$memcache->set("connection_table", serialize(BasicObject::$connection_table), 0, 0); /* No expire */ + BasicObject::$memcache->set(BasicObject::$memcache_prefix . "connection_table", serialize(BasicObject::$connection_table), 0, 0); /* No expire */ } } private static function store_tables() { if(BasicObject::$memcache) { - BasicObject::$memcache->set("tables", serialize(BasicObject::$tables), 0, 0); /* No expire */ + BasicObject::$memcache->set(BasicObject::$memcache_prefix . "tables", serialize(BasicObject::$tables), 0, 0); /* No expire */ } } private static function store_columns() { if(BasicObject::$memcache) { - BasicObject::$memcache->set("columns", serialize(BasicObject::$columns), 0, 0); /* No expire */ + BasicObject::$memcache->set(BasicObject::$memcache_prefix . "columns", serialize(BasicObject::$columns), 0, 0); /* No expire */ } } diff --git a/tests/DatabaseTestCase.php b/tests/DatabaseTestCase.php index c02ef8e..4e9d386 100644 --- a/tests/DatabaseTestCase.php +++ b/tests/DatabaseTestCase.php @@ -6,7 +6,7 @@ class DatabaseTestCase extends PHPUnit_Framework_TestCase { public static function setUpBeforeClass() { global $cache; db_init(); - BasicObject::enable_structure_cache(MC::get_instance()); + BasicObject::enable_structure_cache(MC::get_instance(), "bo_unit_test_"); if($cache) { BasicObject::enable_cache(); } else { @@ -19,7 +19,7 @@ public function setUp() { } public static function tearDownAfterClass() { - BasicObject::clear_structure_cache(MC::get_instance()); + BasicObject::clear_structure_cache(MC::get_instance(), "bo_unit_test_"); db_close(); } } diff --git a/tests/database.php b/tests/database.php index c261228..12555d9 100644 --- a/tests/database.php +++ b/tests/database.php @@ -29,7 +29,7 @@ function db_init() { $db->query("CREATE DATABASE `{$db_settings['database']}`"); db_select_database(); db_run_file("db.sql"); - BasicObject::clear_structure_cache(MC::get_instance()); + BasicObject::clear_structure_cache(MC::get_instance(), "bo_unit_test_"); } function db_select_database() { diff --git a/tests/suites/BasicObject/CacheTest.php b/tests/suites/BasicObject/CacheTest.php index 29a6526..d6d5769 100644 --- a/tests/suites/BasicObject/CacheTest.php +++ b/tests/suites/BasicObject/CacheTest.php @@ -95,8 +95,6 @@ public function testStructureCacheFill() { $vals[$v] = $prop->getValue(); $this->assertNotEmpty($vals[$v]); } - /*BasicObject::clear_structure_cache(MC::get_instance());*/ - /*BasicObject::*/ } public function testStructureCacheRestore() { @@ -110,7 +108,7 @@ public function testStructureCacheRestore() { $prop->setValue(array()); } - BasicObject::enable_structure_cache(MC::get_instance()); + BasicObject::enable_structure_cache(MC::get_instance(), "bo_unit_test_"); foreach($sc_vars as $v => $prop) { $this->assertEquals($vals[$v], $prop->getValue()); } @@ -120,14 +118,27 @@ public function testClearStructureCache() { $sc_vars = $this->getStructureCacheVariables(); Model1::from_id(1); Model1::selection(array('model2.int1' => 1)); - BasicObject::clear_structure_cache(MC::get_instance()); + BasicObject::clear_structure_cache(MC::get_instance(), "bo_unit_test_"); - BasicObject::enable_structure_cache(MC::get_instance()); + BasicObject::enable_structure_cache(MC::get_instance(), "bo_unit_test_"); foreach($sc_vars as $v => $prop) { $this->assertEmpty($prop->getValue()); } } + public function testClearStructureCachePrefixSeparation() { + $sc_vars = $this->getStructureCacheVariables(); + Model1::from_id(1); + Model1::selection(array('model2.int1' => 1)); + + BasicObject::clear_structure_cache(MC::get_instance(), "bo_unit_test2_"); + + BasicObject::enable_structure_cache(MC::get_instance(), "bo_unit_test_"); + foreach($sc_vars as $v => $prop) { + $this->assertNotEmpty($prop->getValue()); + } + } + private function getStructureCacheVariables() { $ret = array(); $vars = array('column_ids', 'connection_table', 'tables', 'columns');