diff --git a/cake/libs/model/datasources/dbo/dbo_mysql.php b/cake/libs/model/datasources/dbo/dbo_mysql.php index 4644db106..de80df81d 100644 --- a/cake/libs/model/datasources/dbo/dbo_mysql.php +++ b/cake/libs/model/datasources/dbo/dbo_mysql.php @@ -216,7 +216,7 @@ class DboMysql extends DboSource { case 'integer' : case 'float' : case null : - if (is_numeric($data) && strpos($data, ',') === false && $data[0] != '0' && strpos($data, 'e') === false) { + if ((is_int($data) || is_float($data)) && strpos($data, ',') === false && $data[0] != '0' && strpos($data, 'e') === false) { break; } default: diff --git a/cake/libs/model/datasources/dbo_source.php b/cake/libs/model/datasources/dbo_source.php index 222f758d5..71fa5a40e 100644 --- a/cake/libs/model/datasources/dbo_source.php +++ b/cake/libs/model/datasources/dbo_source.php @@ -1691,8 +1691,13 @@ class DboSource extends DataSource { $data .= ')'; } else { if ($quoteValues) { - foreach ($value as $valElement) { - $data .= $this->value($valElement) . ', '; + $isString = ($this->introspectType($value) == 'string'); + foreach ($value as $key => $valElement) { + if ($isString) { + $data .= $this->value($valElement) . ', '; + } else { + $data .= $valElement . ', '; + } } } $data[strlen($data) - 2] = ')'; @@ -1754,7 +1759,9 @@ class DboSource extends DataSource { } elseif (preg_match('/^(?:' . join('\\x20)|(?:', $this->__sqlOps) . '\s*\\x20)/i', $match['1'])) { $match['2'] = str_replace(' AND ', "' AND '", $this->value($match['2'])); } else { - $match['2'] = $this->value($match['2']); + if ($this->introspectType($match['2']) == 'string') { + $match['2'] = $this->value($match['2']); + } } } elseif ($isOp) { $match['1'] = trim($match['1']); @@ -1962,16 +1969,55 @@ class DboSource extends DataSource { * @return integer An integer representing the length of the column */ function length($real) { - $col = str_replace(array(')', 'unsigned'), '', $real); - $limit = null; + if (!preg_match_all('/([\w\s]+)(?:\((\d+)(?:,(\d+))?\))?(\sunsigned)?(\szerofill)?/', $real, $result)) { + trigger_error(__('FIXME: Can\'t parse field: ' . $real, true), E_USER_WARNING); + $col = str_replace(array(')', 'unsigned'), '', $real); + $limit = null; - if (strpos($col, '(') !== false) { - list($col, $limit) = explode('(', $col); + if (strpos($col, '(') !== false) { + list($col, $limit) = explode('(', $col); + } + if ($limit != null) { + return intval($limit); + } + return null; } - if ($limit != null) { - return intval($limit); + + $types = array( + 'int' => 1, + 'decimal' => 2, + 'dec' => 2, + 'numeric' => 2, + 'tinyint' => 1, + 'smallint' => 1, + 'mediumint' => 1, + 'integer' => 1, + 'bigint' => 1 + ); + + list($real, $type, $length, $offset, $sign, $zerofill) = $result; + $typeArr = $type; + $type = $type[0]; + $length = $length[0]; + + if (isset($types[$type])) { + $length += $types[$type]; + if (!empty($sign)) { + $length--; + } + } elseif (in_array($type, array('enum', 'set'))) { + $length = 0; + foreach ($typeArr as $key => $enumValue) { + if ($key == 0) { + continue; + } + $tmpLength = strlen($enumValue); + if ($tmpLength > $length) { + $length = $tmpLength; + } + } } - return null; + return intval($length); } /** * Translates between PHP boolean values and Database (faked) boolean values @@ -2174,6 +2220,56 @@ class DboSource extends DataSource { } return $join; } +/** + * Guesses the data type of an array + * + * @param string $value + * @return void + * @access public + */ + function introspectType($value) { + if (!is_array($value)) { + if (is_float($value) || preg_match('/^[\d]+\.[\d]+$/', $value)) { + return 'float'; + } + if (is_int($value) || preg_match('/^[\d]+$/', $value)) { + return 'integer'; + } + return 'string'; + } + + $isAllFloat = $isAllInt = true; + $containsFloat = $containsInt = $containsString = false; + foreach ($value as $key => $valElement) { + $valElement = trim($valElement); + if (!is_float($valElement) && !preg_match('/^[\d]+\.[\d]+$/', $valElement)) { + $isAllFloat = false; + } else { + $containsFloat = true; + continue; + } + if (!is_int($valElement) && !preg_match('/^[\d]+$/', $valElement)) { + $isAllInt = false; + } else { + $containsInt = true; + continue; + } + $containsString = true; + } + + if ($isAllFloat) { + return 'float'; + } + if ($isAllInt) { + return 'integer'; + } + + if ($containsInt && !$containsString) { + return 'integer'; + } + + return 'string'; + } } ?> \ No newline at end of file diff --git a/cake/tests/cases/libs/model/datasources/dbo_source.test.php b/cake/tests/cases/libs/model/datasources/dbo_source.test.php index f0293c9e7..86c4a6e49 100644 --- a/cake/tests/cases/libs/model/datasources/dbo_source.test.php +++ b/cake/tests/cases/libs/model/datasources/dbo_source.test.php @@ -983,6 +983,7 @@ class DboSourceTest extends CakeTestCase { $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding); $result = $this->db->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet); + $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+/', $result); $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE/', $result); $this->assertPattern('/\s+WHERE\s+`TestModel6`.`test_model5_id`\s+IN\s+\({\$__cakeID__\$}\)/', $result); @@ -1064,6 +1065,7 @@ class DboSourceTest extends CakeTestCase { $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding); $result = $this->db->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet); + $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+/', $result); $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result); $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+IN\s+\({\$__cakeID__\$}\)(?:\))?/', $result); @@ -2200,6 +2202,137 @@ class DboSourceTest extends CakeTestCase { $result = $this->db->calculate($this->Model, 'max', array('`Model`.`id`', 'id')); $this->assertEqual($result, 'MAX(`Model`.`id`) AS `id`'); } + + function testLength() { + $result = $this->db->length('varchar(255)'); + $expected = 255; + $this->assertIdentical($result, $expected); + + $result = $this->db->length('int(11)'); + $expected = 11; + $this->assertIdentical($result, $expected); + + $result = $this->db->length('decimal(5,2)'); + $expected = 6; + $this->assertIdentical($result, $expected); + + $result = $this->db->length("enum('test','me','now')"); + $expected = 4; + $this->assertIdentical($result, $expected); + + $result = $this->db->length("set('a','b','cd')"); + $expected = 2; + $this->assertIdentical($result, $expected); + } + + function testBuildIndex() { + $data = array( + 'PRIMARY' => array('column' => 'id') + ); + $result = $this->db->buildIndex($data); + $expected = array('PRIMARY KEY (`id`)'); + $this->assertIdentical($result, $expected); + + $data = array( + 'MyIndex' => array('column' => 'id', 'unique' => true) + ); + $result = $this->db->buildIndex($data); + $expected = array('UNIQUE KEY MyIndex (`id`)'); + $this->assertEqual($result, $expected); + + $data = array( + 'MyIndex' => array('column' => array('id', 'name'), 'unique' => true) + ); + $result = $this->db->buildIndex($data); + $expected = array('UNIQUE KEY MyIndex (`id`, `name`)'); + $this->assertEqual($result, $expected); + } + + function testbuildColumn() { + $data = array( + 'name' => 'testName', + 'type' => 'varchar(255)', + 'default', + 'null' => true, + 'key' + ); + $this->db->buildColumn($data); + $this->assertError(); + + $this->db->columns = array('varchar(255)' => 1); + $data = array( + 'name' => 'testName', + 'type' => 'varchar(255)', + 'default', + 'null' => true, + 'key' + ); + $result = $this->db->buildColumn($data); + $expected = '`testName` DEFAULT NULL'; + $this->assertEqual($result, $expected); + } + + function testIntrospectType() { + $this->assertEqual($this->db->introspectType(0), 'integer'); + $this->assertEqual($this->db->introspectType(2), 'integer'); + $this->assertEqual($this->db->introspectType('2'), 'integer'); + $this->assertEqual($this->db->introspectType('2.2'), 'float'); + $this->assertEqual($this->db->introspectType(2.2), 'float'); + $this->assertEqual($this->db->introspectType('stringme'), 'string'); + $this->assertEqual($this->db->introspectType('0stringme'), 'string'); + + + $data = array(2.2); + $this->assertEqual($this->db->introspectType($data), 'float'); + + $data = array('2.2'); + $this->assertEqual($this->db->introspectType($data), 'float'); + + $data = array(2); + $this->assertEqual($this->db->introspectType($data), 'integer'); + + $data = array('2'); + $this->assertEqual($this->db->introspectType($data), 'integer'); + + $data = array('string'); + $this->assertEqual($this->db->introspectType($data), 'string'); + + + $data = array(2.2, '2.2'); + $this->assertEqual($this->db->introspectType($data), 'float'); + + $data = array(2, '2'); + $this->assertEqual($this->db->introspectType($data), 'integer'); + + $data = array('string one', 'string two'); + $this->assertEqual($this->db->introspectType($data), 'string'); + + + $data = array('2.2', 3); + $this->assertEqual($this->db->introspectType($data), 'integer'); + + $data = array('2.2', '0stringme'); + $this->assertEqual($this->db->introspectType($data), 'string'); + + $data = array(2.2, 3); + $this->assertEqual($this->db->introspectType($data), 'integer'); + + $data = array(2.2, '0stringme'); + $this->assertEqual($this->db->introspectType($data), 'string'); + + + $data = array(2, 'stringme'); + $this->assertEqual($this->db->introspectType($data), 'string'); + + $data = array(2, '2.2', 'stringgme'); + $this->assertEqual($this->db->introspectType($data), 'string'); + + $data = array(2, '2.2'); + $this->assertEqual($this->db->introspectType($data), 'integer'); + + $data = array(2, 2.2); + $this->assertEqual($this->db->introspectType($data), 'integer'); + } } ?> \ No newline at end of file diff --git a/cake/tests/cases/libs/model/model.test.php b/cake/tests/cases/libs/model/model.test.php index 27f4c0327..93535ba3f 100644 --- a/cake/tests/cases/libs/model/model.test.php +++ b/cake/tests/cases/libs/model/model.test.php @@ -41,7 +41,7 @@ class ModelTest extends CakeTestCase { var $fixtures = array( 'core.category', 'core.category_thread', 'core.user', 'core.article', 'core.featured', 'core.article_featureds_tags', - 'core.article_featured', 'core.articles', 'core.tag', 'core.articles_tag', 'core.comment', 'core.attachment', + 'core.article_featured', 'core.articles', 'core.numeric_article', 'core.tag', 'core.articles_tag', 'core.comment', 'core.attachment', 'core.apple', 'core.sample', 'core.another_article', 'core.advertisement', 'core.home', 'core.post', 'core.author', 'core.project', 'core.thread', 'core.message', 'core.bid', 'core.portfolio', 'core.item', 'core.items_portfolio', 'core.syfile', 'core.image', 'core.device_type', 'core.device_type_category', 'core.feature_set', 'core.exterior_type_category', @@ -675,6 +675,20 @@ class ModelTest extends CakeTestCase { $this->assertEqual($result, $expected); } + function testConditionalNumerics() { + $this->loadFixtures('NumericArticle'); + $NumericArticle =& new NumericArticle(); + $data = array('title' => '12345abcde'); + $result = $NumericArticle->find($data); + $this->assertTrue(!empty($result)); + + // @TODO: make this pass in Cake 2.0 with passing the column around in db->value() + // SELECT * from articles WHERE title = 12345 // will find the article with title = 12345abcde, too : / + // $data = array('title' => '12345'); + // $result = $NumericArticle->find($data); + // $this->assertTrue(empty($result)); + } + function testFindAll() { $this->loadFixtures('User'); $TestModel =& new User(); @@ -2408,6 +2422,7 @@ class ModelTest extends CakeTestCase { $this->assertTrue(Set::matches('/Post[1][title=Un-Baleeted First Post]', $result)); $this->assertTrue(Set::matches('/Post[2][title=Just update the title]', $result)); } + $this->assertEqual($TestModel->validationErrors, $errors); $TestModel->validate = array('title' => VALID_NOT_EMPTY, 'author_id' => 'numeric'); @@ -3008,6 +3023,79 @@ class ModelTest extends CakeTestCase { // $this->assertEqual($TestModel->invalidFields(), array('body' => 'This field cannot be left blank')); // } + function testFindAllWithConditionsHavingMixedDataTypes() { + $this->loadFixtures('Article'); + $TestModel =& new Article(); + $expected = array( + array( + 'Article' => array( + 'id' => 1, + 'user_id' => 1, + 'title' => 'First Article', + 'body' => 'First Article Body', + 'published' => 'Y', + 'created' => '2007-03-18 10:39:23', + 'updated' => '2007-03-18 10:41:31' + ) + ), + array( + 'Article' => array( + 'id' => 2, + 'user_id' => 3, + 'title' => 'Second Article', + 'body' => 'Second Article Body', + 'published' => 'Y', + 'created' => '2007-03-18 10:41:23', + 'updated' => '2007-03-18 10:43:31' + ) + ) + ); + $conditions = array('id' => array('1', 2)); + $recursive = -1; + $result = $TestModel->find('all', compact('conditions', 'recursive')); + $this->assertEqual($result, $expected); + + + $conditions = array('id' => array('1', 2, '3.0')); + $result = $TestModel->find('all', compact('recursive', 'conditions')); + $expected = array( + array( + 'Article' => array( + 'id' => 1, + 'user_id' => 1, + 'title' => 'First Article', + 'body' => 'First Article Body', + 'published' => 'Y', + 'created' => '2007-03-18 10:39:23', + 'updated' => '2007-03-18 10:41:31' + ) + ), + array( + 'Article' => array( + 'id' => 2, + 'user_id' => 3, + 'title' => 'Second Article', + 'body' => 'Second Article Body', + 'published' => 'Y', + 'created' => '2007-03-18 10:41:23', + 'updated' => '2007-03-18 10:43:31' + ) + ), + array( + 'Article' => array( + 'id' => 3, + 'user_id' => 1, + 'title' => 'Third Article', + 'body' => 'Third Article Body', + 'published' => 'Y', + 'created' => '2007-03-18 10:43:23', + 'updated' => '2007-03-18 10:45:31' + ) + ) + ); + $this->assertEqual($result, $expected); + } + function testMultipleValidation() { $TestModel =& new ValidationTest(); } @@ -3932,8 +4020,10 @@ class ModelTest extends CakeTestCase { $Article =& new Article(); $this->db->_queryCache = array(); - $finalQuery = 'SELECT title, published FROM ' . $this->db->fullTableName('articles') . ' WHERE ' . $this->db->fullTableName('articles') . '.id = ' . $this->db->value('1') . ' AND ' . $this->db->fullTableName('articles') . '.published = ' . $this->db->value('Y'); + $finalQuery = 'SELECT title, published FROM ' . $this->db->fullTableName('articles') . ' WHERE ' . $this->db->fullTableName('articles') . '.id = ' . $this->db->value(1) . ' AND ' . $this->db->fullTableName('articles') . '.published = ' . $this->db->value('Y'); + $query = 'SELECT title, published FROM ' . $this->db->fullTableName('articles') . ' WHERE ' . $this->db->fullTableName('articles') . '.id = ? AND ' . $this->db->fullTableName('articles') . '.published = ?'; + $params = array(1, 'Y'); $result = $Article->query($query, $params); $expected = array('0' => array($this->db->fullTableName('articles', false) => array('title' => 'First Article', 'published' => 'Y'))); diff --git a/cake/tests/cases/libs/model/models.php b/cake/tests/cases/libs/model/models.php index cb818c9e2..ac871d577 100644 --- a/cake/tests/cases/libs/model/models.php +++ b/cake/tests/cases/libs/model/models.php @@ -134,6 +134,16 @@ class Article extends CakeTestModel { return true; } } +/** + * Short description for class. + * + * @package cake.tests + * @subpackage cake.tests.cases.libs.model + */ +class NumericArticle extends CakeTestModel { + var $name = 'NumericArticle'; + var $useTable = 'numeric_articles'; +} /** * Short description for class. * diff --git a/cake/tests/cases/libs/object.test.php b/cake/tests/cases/libs/object.test.php index 7196739b7..57fe2a6a4 100644 --- a/cake/tests/cases/libs/object.test.php +++ b/cake/tests/cases/libs/object.test.php @@ -254,6 +254,10 @@ class ObjectTest extends UnitTestCase { $expected = 'This is the TestsPluginsTestsController index view'; $this->assertEqual($result, $expected); + $result = $this->object->requestAction('/test_plugin/tests_plugins_tests/index/some_param', array('return')); + $expected = 'This is the TestsPluginsTestsController index view'; + $this->assertEqual($result, $expected); + $result = $this->object->requestAction(array('controller' => 'tests_plugins_tests', 'action' => 'index', 'plugin' => 'test_plugin'), array('return')); $expected = 'This is the TestsPluginsTestsController index view'; $this->assertEqual($result, $expected); diff --git a/cake/tests/fixtures/numeric_article_fixture.php b/cake/tests/fixtures/numeric_article_fixture.php new file mode 100644 index 000000000..9d1f7a175 --- /dev/null +++ b/cake/tests/fixtures/numeric_article_fixture.php @@ -0,0 +1,49 @@ + + * Copyright 2005-2008, Cake Software Foundation, Inc. + * 1785 E. Sahara Avenue, Suite 490-204 + * Las Vegas, Nevada 89104 + * + * Licensed under The Open Group Test Suite License + * Redistributions of files must retain the above copyright notice. + * + * @filesource + * @copyright Copyright 2005-2008, Cake Software Foundation, Inc. + * @link https://trac.cakephp.org/wiki/Developement/TestSuite CakePHP(tm) Tests + * @package cake.tests + * @subpackage cake.tests.fixtures + * @since CakePHP(tm) v 1.2.0.4667 + * @version $Revision$ + * @modifiedby $LastChangedBy$ + * @lastmodified $Date$ + * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License + */ +/** + * Short description for class. + * + * @package cake.tests + * @subpackage cake.tests.fixtures + */ +class NumericArticleFixture extends CakeTestFixture { + var $name = 'NumericArticle'; + var $fields = array( + 'id' => array('type' => 'integer', 'key' => 'primary'), + 'title' => array('type' => 'string', 'null' => false), + 'created' => 'datetime', + 'updated' => 'datetime' + ); + var $records = array( + array('title' => 'First Article', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'), + array('title' => '12345abcde', 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'), + ); +} + +?> \ No newline at end of file