From 8f29f59c1a61bf44b80b7f2dc44df2d2fccaacd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Lorenzo=20Rodr=C3=ADguez?= Date: Thu, 17 Dec 2009 14:42:46 -0430 Subject: [PATCH] Enclosing virtual fields in parentheses to avoid SQL errors Added new tests to improve code coverage on virtual fields --- cake/libs/model/datasources/dbo_source.php | 8 +- .../model/datasources/dbo_source.test.php | 121 +++++++++++++++++- 2 files changed, 124 insertions(+), 5 deletions(-) diff --git a/cake/libs/model/datasources/dbo_source.php b/cake/libs/model/datasources/dbo_source.php index cb335dc85..f157a40c5 100644 --- a/cake/libs/model/datasources/dbo_source.php +++ b/cake/libs/model/datasources/dbo_source.php @@ -1788,7 +1788,7 @@ class DboSource extends DataSource { foreach ($fields as $field) { $virtualField = $this->name("{$alias}__{$field}"); $expression = $this->__quoteFields($model->getVirtualField($field)); - $virtual[] = $expression . " {$this->alias} {$virtualField}"; + $virtual[] = '(' .$expression . ") {$this->alias} {$virtualField}"; } return $virtual; } @@ -2123,7 +2123,9 @@ class DboSource extends DataSource { break; } } - + if ($virtual) { + return "({$key}) {$operator} {$value}"; + } return "{$key} {$operator} {$value}"; } @@ -2241,7 +2243,7 @@ class DboSource extends DataSource { $key = trim($key); if (!preg_match('/\s/', $key) && !strpos($key,'.')) { if (is_object($model) && $model->isVirtualField($key)) { - $key = $this->__quoteFields($model->getVirtualField($key)); + $key = '('.$this->__quoteFields($model->getVirtualField($key)).')'; } else { $key = $this->name($key); } 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 717f38996..1c2a573a8 100644 --- a/cake/tests/cases/libs/model/datasources/dbo_source.test.php +++ b/cake/tests/cases/libs/model/datasources/dbo_source.test.php @@ -3609,8 +3609,8 @@ class DboSourceTest extends CakeTestCase { $this->testDb->fieldParameters['param'] = array( 'value' => 'COLLATE', 'quote' => false, - 'join' => ' ', - 'column' => 'Collate', + 'join' => ' ', + 'column' => 'Collate', 'position' => 'beforeDefault', 'options' => array('GOOD', 'OK') ); @@ -4081,5 +4081,122 @@ class DboSourceTest extends CakeTestCase { $this->assertNoPattern('/Num:/s', $contents); $this->assertNoPattern('/Took:/s', $contents); } + + function testVirtualFields() { + $this->loadFixtures('Article'); + + $Article =& ClassRegistry::init('Article'); + $Article->virtualFields = array( + 'this_moment' => 'NOW()', + 'two' => '1 + 1', + 'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') . + ' WHERE Article.id = ' . $this->db->fullTableName('comments'). '.article_id' + ); + $result = $this->db->fields($Article); + $expected = array( + '`Article`.`id`', + '`Article`.`user_id`', + '`Article`.`title`', + '`Article`.`body`', + '`Article`.`published`', + '`Article`.`created`', + '`Article`.`updated`', + '(NOW()) AS `Article__this_moment`', + '(1 + 1) AS `Article__two`', + '(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) AS `Article__comment_count`' + ); + $this->assertEqual($expected,$result); + + $result = $this->db->fields($Article,null,array('this_moment','title')); + $expected = array( + '`Article`.`title`', + '(NOW()) AS `Article__this_moment`', + ); + $this->assertEqual($expected,$result); + } + + function testVirtualFieldsInConditions() { + $this->loadFixtures('Article'); + + $Article =& ClassRegistry::init('Article'); + $Article->virtualFields = array( + 'this_moment' => 'NOW()', + 'two' => '1 + 1', + 'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') . + ' WHERE Article.id = ' . $this->db->fullTableName('comments'). '.article_id' + ); + $conditions = array('two' => 2); + $result = $this->db->conditions($conditions,true,false,$Article); + $expected = '(1 + 1) = 2'; + $this->assertEqual($expected,$result); + + $conditions = array('this_moment BETWEEN ? AND ?' => array(1,2)); + $expected = 'NOW() BETWEEN 1 AND 2'; + $result = $this->db->conditions($conditions,true,false,$Article); + $this->assertEqual($expected,$result); + + $conditions = array('comment_count >' => 5); + $expected = '(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) > 5'; + $result = $this->db->conditions($conditions,true,false,$Article); + $this->assertEqual($expected,$result); + + $conditions = array('NOT' => array('two' => 2)); + $result = $this->db->conditions($conditions,true,false,$Article); + $expected = 'NOT ((1 + 1) = 2)'; + $this->assertEqual($expected,$result); + } + + function testVirtualFieldsInOrder() { + $this->loadFixtures('Article'); + + $Article =& ClassRegistry::init('Article'); + $Article->virtualFields = array( + 'this_moment' => 'NOW()', + 'two' => '1 + 1', + ); + $order = array('two','this_moment'); + $result = $this->db->order($order,'ASC',$Article); + $expected = ' ORDER BY (1 + 1) ASC, (NOW()) ASC'; + $this->assertEqual($expected,$result); + } + + function testVirtualFieldsInCalculate() { + $this->loadFixtures('Article'); + + $Article =& ClassRegistry::init('Article'); + $Article->virtualFields = array( + 'this_moment' => 'NOW()', + 'two' => '1 + 1', + 'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') . + ' WHERE Article.id = ' . $this->db->fullTableName('comments'). '.article_id' + ); + + $result = $this->db->calculate($Article,'count',array('this_moment')); + $expected = 'COUNT(NOW()) AS `count`'; + $this->assertEqual($expected,$result); + + $result = $this->db->calculate($Article,'max',array('comment_count')); + $expected = 'MAX(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) AS `comment_count`'; + $this->assertEqual($expected,$result); + } + + function testVirtualFieldsFetch() { + $this->loadFixtures('Article','Comment'); + + $Article =& ClassRegistry::init('Article'); + $Article->virtualFields = array( + 'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') . + ' WHERE Article.id = ' . $this->db->fullTableName('comments'). '.article_id' + ); + + $conditions = array('comment_count >' => 2); + $query = 'SELECT ' . join(',',$this->db->fields($Article,null,array('id','comment_count'))) . + ' FROM ' . $this->db->fullTableName($Article) . ' Article ' . $this->db->conditions($conditions,true,true,$Article); + $result = $this->db->fetchAll($query); + $expected = array(array( + 'Article' => array('id' => 1, 'comment_count' => 4) + )); + $this->assertEqual($expected,$result); + } } ?> \ No newline at end of file