From cd562f52bad9aca436335dfa0b5b26dab954c7f4 Mon Sep 17 00:00:00 2001 From: Jose Lorenzo Rodriguez Date: Sat, 7 Jan 2012 00:37:50 -0430 Subject: [PATCH 01/11] Fixing a couple failing tests on windows using sqlserver --- lib/Cake/Model/Datasource/Database/Sqlserver.php | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php index 9e60c1622..df5cd8884 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -645,14 +645,7 @@ class Sqlserver extends DboSource { $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' ON'); } - $table = $this->fullTableName($table); - $fields = implode(', ', array_map(array(&$this, 'name'), $fields)); - $this->begin(); - foreach ($values as $value) { - $holder = implode(', ', array_map(array(&$this, 'value'), $value)); - $this->_execute("INSERT INTO {$table} ({$fields}) VALUES ({$holder})"); - } - $this->commit(); + parent::insertMulti($table, $fields, $values); if ($hasPrimaryKey) { $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' OFF'); @@ -717,9 +710,6 @@ class Sqlserver extends DboSource { * @return string */ protected function _getPrimaryKey($model) { - if (!is_object($model)) { - $model = new Model(false, $model); - } $schema = $this->describe($model); foreach ($schema as $field => $props) { if (isset($props['key']) && $props['key'] == 'primary') { From ba097d404fecc1336526fbd9485ef087eabe8886 Mon Sep 17 00:00:00 2001 From: Jose Lorenzo Rodriguez Date: Sat, 7 Jan 2012 01:04:02 -0430 Subject: [PATCH 02/11] Explicitly using a fetch mode in SQLServer, not doing it causes serious memory leaks --- lib/Cake/Model/Datasource/Database/Sqlserver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php index df5cd8884..edb29603d 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -182,7 +182,7 @@ class Sqlserver extends DboSource { } else { $tables = array(); - while ($line = $result->fetch()) { + while ($line = $result->fetch(PDO::FETCH_NUM)) { $tables[] = $line[0]; } @@ -222,7 +222,7 @@ class Sqlserver extends DboSource { throw new CakeException(__d('cake_dev', 'Could not describe table for %s', $table)); } - foreach ($cols as $column) { + while ($column = $cols->fetch(PDO::FETCH_OBJ)) { $field = $column->Field; $fields[$field] = array( 'type' => $this->column($column), From abb370fe3f3a03f4552cbef225623b7b68f773c7 Mon Sep 17 00:00:00 2001 From: Jose Lorenzo Rodriguez Date: Sat, 7 Jan 2012 01:39:40 -0430 Subject: [PATCH 03/11] Fixing windows failing test case on the debug function --- lib/Cake/basics.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/basics.php b/lib/Cake/basics.php index 9f11f3397..623a95d96 100644 --- a/lib/Cake/basics.php +++ b/lib/Cake/basics.php @@ -76,7 +76,7 @@ function debug($var = false, $showHtml = null, $showFrom = true) { $lineInfo = ''; if ($showFrom) { $calledFrom = debug_backtrace(); - $file = substr(str_replace(ROOT, '', $calledFrom[0]['file']), 1); + $file = substr(str_ireplace(ROOT, '', $calledFrom[0]['file']), 1); $line = $calledFrom[0]['line']; } $html = << Date: Sat, 7 Jan 2012 02:09:47 -0430 Subject: [PATCH 04/11] Fixing a few SqlServer failing tests --- .../Datasource/Database/SqlserverTest.php | 20 ++++++++++++++++--- .../Case/Model/Datasource/DboSourceTest.php | 3 +++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php index 05890dac1..7838b46ff 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php @@ -111,7 +111,7 @@ class SqlserverTestDb extends Sqlserver { * * @package Cake.Test.Case.Model.Datasource.Database */ -class SqlserverTestModel extends Model { +class SqlserverTestModel extends CakeTestModel { /** * name property @@ -183,7 +183,7 @@ class SqlserverTestModel extends Model { * * @package Cake.Test.Case.Model.Datasource.Database */ -class SqlserverClientTestModel extends Model { +class SqlserverClientTestModel extends CakeTestModel { /** * name property * @@ -224,6 +224,20 @@ class SqlserverTestResultIterator extends ArrayIterator { * @return void */ public function closeCursor() {} + +/** + * fetch method + * + * @return void + */ + public function fetch() { + if (!$this->valid()) { + return null; + } + $current = $this->current(); + $this->next(); + return $current; + } } /** @@ -283,7 +297,7 @@ class SqlserverTest extends CakeTestCase { * @return void */ public function testQuoting() { - $expected = "1.200000"; + $expected = "1.2"; $result = $this->db->value(1.2, 'float'); $this->assertSame($expected, $result); diff --git a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php index 17dbad4f4..1e93a9d9e 100644 --- a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php @@ -493,6 +493,9 @@ class DboSourceTest extends CakeTestCase { * @return void */ public function testValue() { + if ($this->db instanceof Sqlserver) { + $this->markTestSkipped('Cannot run this test with SqlServer'); + } $result = $this->db->value('{$__cakeForeignKey__$}'); $this->assertEquals($result, '{$__cakeForeignKey__$}'); From 1991430584fc7f41eb15833926f37864162075a6 Mon Sep 17 00:00:00 2001 From: Jose Lorenzo Rodriguez Date: Sat, 7 Jan 2012 02:17:27 -0430 Subject: [PATCH 05/11] Removing test that does not relate anymore to SqlServer datasource --- .../Datasource/Database/SqlserverTest.php | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php index 7838b46ff..95394bf62 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php @@ -600,43 +600,6 @@ class SqlserverTest extends CakeTestCase { $this->assertNull($result); } -/** - * testInsertMulti - * - * @return void - */ - public function testInsertMulti() { - $this->db->describe = $this->model->schema(); - - $fields = array('id', 'name', 'login'); - $values = array( - array(1, 'Larry', 'PhpNut'), - array(2, 'Renan', 'renan.saddam')); - $this->db->simulated = array(); - $this->db->insertMulti($this->model, $fields, $values); - $result = $this->db->simulated; - $expected = array( - 'SET IDENTITY_INSERT [sqlserver_test_models] ON', - "INSERT INTO [sqlserver_test_models] ([id], [name], [login]) VALUES (1, N'Larry', N'PhpNut')", - "INSERT INTO [sqlserver_test_models] ([id], [name], [login]) VALUES (2, N'Renan', N'renan.saddam')", - 'SET IDENTITY_INSERT [sqlserver_test_models] OFF' - ); - $this->assertEquals($expected, $result); - - $fields = array('name', 'login'); - $values = array( - array('Larry', 'PhpNut'), - array('Renan', 'renan.saddam')); - $this->db->simulated = array(); - $this->db->insertMulti($this->model, $fields, $values); - $result = $this->db->simulated; - $expected = array( - "INSERT INTO [sqlserver_test_models] ([name], [login]) VALUES (N'Larry', N'PhpNut')", - "INSERT INTO [sqlserver_test_models] ([name], [login]) VALUES (N'Renan', N'renan.saddam')", - ); - $this->assertEquals($expected, $result); - } - /** * SQL server < 11 doesn't have proper limit/offset support, test that our hack works. * From 87924414fce268f085069383e83e391799a9d6f3 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 7 Jan 2012 10:45:35 -0500 Subject: [PATCH 06/11] Update Configure::load() to use Set::merge() This fixes some of the awkward behavior that using array_merge_recursive() could create. Fixes #2441 --- lib/Cake/Core/Configure.php | 2 +- lib/Cake/Test/Case/Core/ConfigureTest.php | 2 ++ lib/Cake/Test/test_app/Config/var_test.php | 5 ++++- lib/Cake/Test/test_app/Config/var_test2.php | 6 +++++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Core/Configure.php b/lib/Cake/Core/Configure.php index 2772eb084..67cabfc50 100644 --- a/lib/Cake/Core/Configure.php +++ b/lib/Cake/Core/Configure.php @@ -312,7 +312,7 @@ class Configure { $keys = array_keys($values); foreach ($keys as $key) { if (($c = self::read($key)) && is_array($values[$key]) && is_array($c)) { - $values[$key] = array_merge_recursive($c, $values[$key]); + $values[$key] = Set::merge($c, $values[$key]); } } } diff --git a/lib/Cake/Test/Case/Core/ConfigureTest.php b/lib/Cake/Test/Case/Core/ConfigureTest.php index 746412fdf..5e94b5749 100644 --- a/lib/Cake/Test/Case/Core/ConfigureTest.php +++ b/lib/Cake/Test/Case/Core/ConfigureTest.php @@ -224,6 +224,8 @@ class ConfigureTest extends CakeTestCase { $this->assertEquals('value2', Configure::read('Read')); $this->assertEquals('buried2', Configure::read('Deep.Second.SecondDeepest')); $this->assertEquals('buried', Configure::read('Deep.Deeper.Deepest')); + $this->assertEquals('Overwrite', Configure::read('TestAcl.classname')); + $this->assertEquals('one', Configure::read('TestAcl.custom')); } /** diff --git a/lib/Cake/Test/test_app/Config/var_test.php b/lib/Cake/Test/test_app/Config/var_test.php index e0f3ae2a1..44c345563 100644 --- a/lib/Cake/Test/test_app/Config/var_test.php +++ b/lib/Cake/Test/test_app/Config/var_test.php @@ -5,5 +5,8 @@ $config = array( 'Deeper' => array( 'Deepest' => 'buried' ) + ), + 'TestAcl' => array( + 'classname' => 'Original' ) -); \ No newline at end of file +); diff --git a/lib/Cake/Test/test_app/Config/var_test2.php b/lib/Cake/Test/test_app/Config/var_test2.php index 33345b4ec..745b75dbc 100644 --- a/lib/Cake/Test/test_app/Config/var_test2.php +++ b/lib/Cake/Test/test_app/Config/var_test2.php @@ -5,5 +5,9 @@ $config = array( 'Second' => array( 'SecondDeepest' => 'buried2' ) + ), + 'TestAcl' => array( + 'classname' => 'Overwrite', + 'custom' => 'one' ) -); \ No newline at end of file +); From beced84d2d96b7580c78c1243255b683a670de29 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 7 Jan 2012 11:58:35 -0500 Subject: [PATCH 07/11] Fix illegal offset caused by TranslateBehavior. If you load TranslateBehavior at runtime in a disabled state, the enabled flag would be interpreted as an association and cause errors. Fixes #2443 --- lib/Cake/Model/BehaviorCollection.php | 4 +++- .../Test/Case/Model/BehaviorCollectionTest.php | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Model/BehaviorCollection.php b/lib/Cake/Model/BehaviorCollection.php index 323cc63f6..1e154eaab 100644 --- a/lib/Cake/Model/BehaviorCollection.php +++ b/lib/Cake/Model/BehaviorCollection.php @@ -106,6 +106,9 @@ class BehaviorCollection extends ObjectCollection { $alias = $behavior; $behavior = $config['className']; } + $configDisabled = isset($config['enabled']) && $config['enabled'] === false; + unset($config['enabled'], $config['className']); + list($plugin, $name) = pluginSplit($behavior, true); if (!isset($alias)) { $alias = $name; @@ -165,7 +168,6 @@ class BehaviorCollection extends ObjectCollection { } } - $configDisabled = isset($config['enabled']) && $config['enabled'] === false; if (!in_array($alias, $this->_enabled) && !$configDisabled) { $this->enable($alias); } elseif ($configDisabled) { diff --git a/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php b/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php index f2cea74f8..b9022320b 100644 --- a/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php +++ b/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php @@ -419,9 +419,22 @@ class BehaviorCollectionTest extends CakeTestCase { */ public $fixtures = array( 'core.apple', 'core.sample', 'core.article', 'core.user', 'core.comment', - 'core.attachment', 'core.tag', 'core.articles_tag' + 'core.attachment', 'core.tag', 'core.articles_tag', 'core.translate' ); +/** + * Test load() with enabled => false + * + */ + public function testLoadDisabled() { + $Apple = new Apple(); + $this->assertSame($Apple->Behaviors->attached(), array()); + + $Apple->Behaviors->load('Translate', array('enabled' => false)); + $this->assertTrue($Apple->Behaviors->attached('Translate')); + $this->assertFalse($Apple->Behaviors->enabled('Translate')); + } + /** * Tests loading aliased behaviors */ From 9a67a7070383abe3d746c9f71e386a10e9548863 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 7 Jan 2012 20:24:33 -0500 Subject: [PATCH 08/11] Fix failing test. --- lib/Cake/Test/Case/Model/ModelIntegrationTest.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/Cake/Test/Case/Model/ModelIntegrationTest.php b/lib/Cake/Test/Case/Model/ModelIntegrationTest.php index bd76cd878..5f94c88d5 100644 --- a/lib/Cake/Test/Case/Model/ModelIntegrationTest.php +++ b/lib/Cake/Test/Case/Model/ModelIntegrationTest.php @@ -208,11 +208,11 @@ class ModelIntegrationTest extends BaseModelTest { public function testDynamicBehaviorAttachment() { $this->loadFixtures('Apple', 'Sample', 'Author'); $TestModel = new Apple(); - $this->assertEquals($TestModel->Behaviors->attached(), array()); + $this->assertEquals(array(), $TestModel->Behaviors->attached()); $TestModel->Behaviors->attach('Tree', array('left' => 'left_field', 'right' => 'right_field')); $this->assertTrue(is_object($TestModel->Behaviors->Tree)); - $this->assertEquals($TestModel->Behaviors->attached(), array('Tree')); + $this->assertEquals(array('Tree'), $TestModel->Behaviors->attached()); $expected = array( 'parent' => 'parent_id', @@ -223,16 +223,14 @@ class ModelIntegrationTest extends BaseModelTest { '__parentChange' => false, 'recursive' => -1 ); + $this->assertEquals($expected, $TestModel->Behaviors->Tree->settings['Apple']); - $this->assertEquals($TestModel->Behaviors->Tree->settings['Apple'], $expected); - - $expected['enabled'] = false; $TestModel->Behaviors->attach('Tree', array('enabled' => false)); - $this->assertEquals($TestModel->Behaviors->Tree->settings['Apple'], $expected); - $this->assertEquals($TestModel->Behaviors->attached(), array('Tree')); + $this->assertEquals($expected, $TestModel->Behaviors->Tree->settings['Apple']); + $this->assertEquals(array('Tree'), $TestModel->Behaviors->attached()); $TestModel->Behaviors->detach('Tree'); - $this->assertEquals($TestModel->Behaviors->attached(), array()); + $this->assertEquals(array(), $TestModel->Behaviors->attached()); $this->assertFalse(isset($TestModel->Behaviors->Tree)); } From c548b6b88ac2851578088feb34effb7374efee17 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 8 Jan 2012 12:28:22 -0500 Subject: [PATCH 09/11] Fix issue with find(count) and translated conditions. Because count queries did not have joins created for the translated fields pagination would generate invalid queries. Checking the conditions for translated fields and adding in the correct joins solves that. Extract what would have been duplicated code into methods. Add a few protected properties to keep method signatures sane. The code could be even simpler if the existing find(count) join was removed. Fixes #2349 --- lib/Cake/Model/Behavior/TranslateBehavior.php | 144 +++++++++++++----- .../Model/Behavior/TranslateBehaviorTest.php | 18 +++ 2 files changed, 125 insertions(+), 37 deletions(-) diff --git a/lib/Cake/Model/Behavior/TranslateBehavior.php b/lib/Cake/Model/Behavior/TranslateBehavior.php index 5c2460d06..84a48a627 100644 --- a/lib/Cake/Model/Behavior/TranslateBehavior.php +++ b/lib/Cake/Model/Behavior/TranslateBehavior.php @@ -34,6 +34,20 @@ class TranslateBehavior extends ModelBehavior { */ public $runtime = array(); +/** + * Stores the joinTable object for generating joins. + * + * @var object + */ + var $_joinTable; + +/** + * Stores the runtime model for generating joins. + * + * @var Model + */ + var $_runtimeModel; + /** * Callback * @@ -94,6 +108,7 @@ class TranslateBehavior extends ModelBehavior { } $db = $model->getDataSource(); $RuntimeModel = $this->translateModel($model); + if (!empty($RuntimeModel->tablePrefix)) { $tablePrefix = $RuntimeModel->tablePrefix; } else { @@ -103,8 +118,11 @@ class TranslateBehavior extends ModelBehavior { $joinTable->tablePrefix = $tablePrefix; $joinTable->table = $RuntimeModel->table; + $this->_joinTable = $joinTable; + $this->_runtimeModel = $RuntimeModel; + if (is_string($query['fields']) && 'COUNT(*) AS ' . $db->name('count') == $query['fields']) { - $query['fields'] = 'COUNT(DISTINCT(' . $db->name($model->alias . '.' . $model->primaryKey) . ')) ' . $db->alias . 'count'; + $query['fields'] = 'COUNT(DISTINCT('.$db->name($model->alias . '.' . $model->primaryKey) . ')) ' . $db->alias . 'count'; $query['joins'][] = array( 'type' => 'INNER', 'alias' => $RuntimeModel->alias, @@ -115,6 +133,11 @@ class TranslateBehavior extends ModelBehavior { $RuntimeModel->alias.'.locale' => $locale ) ); + $conditionFields = $this->_checkConditions($model, $query); + foreach ($conditionFields as $field) { + $query = $this->_addJoin($model, $query, $field, $locale); + } + unset($this->_joinTable, $this->_runtimeModel); return $query; } @@ -144,45 +167,92 @@ class TranslateBehavior extends ModelBehavior { unset($query['fields'][$key]); } } - - if (is_array($locale)) { - foreach ($locale as $_locale) { - $model->virtualFields['i18n_' . $field . '_' . $_locale] = 'I18n__' . $field . '__' . $_locale . '.content'; - if (!empty($query['fields'])) { - $query['fields'][] = 'i18n_' . $field . '_' . $_locale; - } - $query['joins'][] = array( - 'type' => 'LEFT', - 'alias' => 'I18n__' . $field . '__' . $_locale, - 'table' => $joinTable, - 'conditions' => array( - $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"), - 'I18n__' . $field . '__' . $_locale . '.model' => $model->name, - 'I18n__' . $field . '__' . $_locale . '.' . $RuntimeModel->displayField => $aliasField, - 'I18n__' . $field . '__' . $_locale . '.locale' => $_locale - ) - ); - } - } else { - $model->virtualFields['i18n_' . $field] = 'I18n__' . $field . '.content'; - if (!empty($query['fields'])) { - $query['fields'][] = 'i18n_' . $field; - } - $query['joins'][] = array( - 'type' => 'INNER', - 'alias' => 'I18n__' . $field, - 'table' => $joinTable, - 'conditions' => array( - $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"), - 'I18n__' . $field . '.model' => $model->name, - 'I18n__' . $field . '.' . $RuntimeModel->displayField => $aliasField, - 'I18n__' . $field . '.locale' => $locale - ) - ); - } + $query = $this->_addJoin($model, $query, $field, $locale); } } $this->runtime[$model->alias]['beforeFind'] = $addFields; + unset($this->_joinTable, $this->_runtimeModel); + return $query; + } + +/** + * Check a query's conditions for translated fields. + * Return an array of translated fields found in the conditions. + * + * @param Model $model The model being read. + * @param array $query The query array. + * @return array The list of translated fields that are in the conditions. + */ + protected function _checkConditions(Model $model, $query) { + $conditionFields = array(); + if (empty($query['conditions']) || (!empty($query['conditions']) && !is_array($query['conditions'])) ) { + return $conditionFields; + } + foreach ($query['conditions'] as $col => $val) { + foreach ($this->settings[$model->alias] as $field => $assoc) { + if (is_numeric($field)) { + $field = $assoc; + } + if (strpos($col, $field) !== false) { + $conditionFields[] = $field; + } + } + } + return $conditionFields; + } + +/** + * Appends a join for translated fields and possibly a field. + * + * @param Model $model The model being worked on. + * @param object $joinTable The jointable object. + * @param array $query The query array to append a join to. + * @param string $field The field name being joined. + * @param mixed $locale The locale(s) having joins added. + * @param boolean $addField Whether or not to add a field. + * @return array The modfied query + */ + protected function _addJoin(Model $model, $query, $field, $locale, $addField = false) { + $db = ConnectionManager::getDataSource($model->useDbConfig); + + $RuntimeModel = $this->_runtimeModel; + $joinTable = $this->_joinTable; + + if (is_array($locale)) { + foreach ($locale as $_locale) { + $model->virtualFields['i18n_' . $field . '_' . $_locale] = 'I18n__' . $field . '__' . $_locale . '.content'; + if (!empty($query['fields']) && is_array($query['fields'])) { + $query['fields'][] = 'i18n_'.$field.'_'.$_locale; + } + $query['joins'][] = array( + 'type' => 'LEFT', + 'alias' => 'I18n__'.$field.'__'.$_locale, + 'table' => $joinTable, + 'conditions' => array( + $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"), + 'I18n__'.$field.'__'.$_locale.'.model' => $model->name, + 'I18n__'.$field.'__'.$_locale.'.'.$RuntimeModel->displayField => $field, + 'I18n__'.$field.'__'.$_locale.'.locale' => $_locale + ) + ); + } + } else { + $model->virtualFields['i18n_' . $field] = 'I18n__' . $field . '.content'; + if (!empty($query['fields']) && is_array($query['fields'])) { + $query['fields'][] = 'i18n_'.$field; + } + $query['joins'][] = array( + 'type' => 'INNER', + 'alias' => 'I18n__'.$field, + 'table' => $joinTable, + 'conditions' => array( + $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"), + 'I18n__'.$field.'.model' => $model->name, + 'I18n__'.$field.'.'.$RuntimeModel->displayField => $field, + 'I18n__'.$field.'.locale' => $locale + ) + ); + } return $query; } diff --git a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php index 89fa6a864..538eb7623 100644 --- a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php +++ b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php @@ -58,6 +58,24 @@ class TranslateBehaviorTest extends CakeTestCase { ClassRegistry::flush(); } +/** + * Test that count queries with conditions get the correct joins + * + * @return void + */ + function testCountWithConditions() { + $this->loadFixtures('Translate', 'TranslatedItem'); + + $Model =& new TranslatedItem(); + $Model->locale = 'eng'; + $result = $Model->find('count', array( + 'conditions' => array( + 'I18n__content.locale' => 'eng' + ) + )); + $this->assertEqual(3, $result); + } + /** * testTranslateModel method * From 3c48552f81f486b8fd7bd9d3dabf9788f9b26018 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 8 Jan 2012 21:40:12 -0500 Subject: [PATCH 10/11] Fix error with more case-sensitive databases. --- lib/Cake/Model/Behavior/TranslateBehavior.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Model/Behavior/TranslateBehavior.php b/lib/Cake/Model/Behavior/TranslateBehavior.php index 84a48a627..8d8067228 100644 --- a/lib/Cake/Model/Behavior/TranslateBehavior.php +++ b/lib/Cake/Model/Behavior/TranslateBehavior.php @@ -135,7 +135,7 @@ class TranslateBehavior extends ModelBehavior { ); $conditionFields = $this->_checkConditions($model, $query); foreach ($conditionFields as $field) { - $query = $this->_addJoin($model, $query, $field, $locale); + $query = $this->_addJoin($model, $query, $field, $field, $locale); } unset($this->_joinTable, $this->_runtimeModel); return $query; @@ -167,7 +167,7 @@ class TranslateBehavior extends ModelBehavior { unset($query['fields'][$key]); } } - $query = $this->_addJoin($model, $query, $field, $locale); + $query = $this->_addJoin($model, $query, $field, $aliasField, $locale); } } $this->runtime[$model->alias]['beforeFind'] = $addFields; @@ -208,11 +208,12 @@ class TranslateBehavior extends ModelBehavior { * @param object $joinTable The jointable object. * @param array $query The query array to append a join to. * @param string $field The field name being joined. + * @param string $aliasField The aliased field name being joined. * @param mixed $locale The locale(s) having joins added. * @param boolean $addField Whether or not to add a field. * @return array The modfied query */ - protected function _addJoin(Model $model, $query, $field, $locale, $addField = false) { + protected function _addJoin(Model $model, $query, $field, $aliasField, $locale, $addField = false) { $db = ConnectionManager::getDataSource($model->useDbConfig); $RuntimeModel = $this->_runtimeModel; @@ -231,7 +232,7 @@ class TranslateBehavior extends ModelBehavior { 'conditions' => array( $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"), 'I18n__'.$field.'__'.$_locale.'.model' => $model->name, - 'I18n__'.$field.'__'.$_locale.'.'.$RuntimeModel->displayField => $field, + 'I18n__'.$field.'__'.$_locale.'.'.$RuntimeModel->displayField => $aliasField, 'I18n__'.$field.'__'.$_locale.'.locale' => $_locale ) ); @@ -248,7 +249,7 @@ class TranslateBehavior extends ModelBehavior { 'conditions' => array( $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"), 'I18n__'.$field.'.model' => $model->name, - 'I18n__'.$field.'.'.$RuntimeModel->displayField => $field, + 'I18n__'.$field.'.'.$RuntimeModel->displayField => $aliasField, 'I18n__'.$field.'.locale' => $locale ) ); From f4c27e04bcad304bf9a3127e778dfce1c82f9ed6 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 8 Jan 2012 21:55:51 -0500 Subject: [PATCH 11/11] Fix errors generated when option['order'] is undefined. Fixes #2447 --- .../Component/PaginatorComponent.php | 2 +- .../Component/PaginatorComponentTest.php | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Controller/Component/PaginatorComponent.php b/lib/Cake/Controller/Component/PaginatorComponent.php index ecc1f2ec4..cc82ab259 100644 --- a/lib/Cake/Controller/Component/PaginatorComponent.php +++ b/lib/Cake/Controller/Component/PaginatorComponent.php @@ -333,7 +333,7 @@ class PaginatorComponent extends Component { $options['order'] = array($options['sort'] => $direction); } - if (!empty($whitelist)) { + if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) { $field = key($options['order']); if (!in_array($field, $whitelist)) { $options['order'] = null; diff --git a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php index fe6c961a3..814fa6b7d 100644 --- a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php @@ -776,6 +776,26 @@ class PaginatorComponentTest extends CakeTestCase { $this->assertEquals($expected, $result['order']); } +/** + * Test that no sort doesn't trigger an error. + * + * @return void + */ + public function testValidateSortNoSort() { + $model = $this->getMock('Model'); + $model->alias = 'model'; + $model->expects($this->any())->method('hasField')->will($this->returnValue(true)); + + $options = array('direction' => 'asc'); + $result = $this->Paginator->validateSort($model, $options, array('title', 'id')); + $this->assertFalse(isset($result['order'])); + + $options = array('order' => 'invalid desc'); + $result = $this->Paginator->validateSort($model, $options, array('title', 'id')); + + $this->assertEquals($options['order'], $result['order']); + } + /** * test that maxLimit is respected *