diff --git a/lib/Cake/Model/Behavior/TranslateBehavior.php b/lib/Cake/Model/Behavior/TranslateBehavior.php index 3ba00ff75..3e495cf24 100644 --- a/lib/Cake/Model/Behavior/TranslateBehavior.php +++ b/lib/Cake/Model/Behavior/TranslateBehavior.php @@ -60,6 +60,25 @@ class TranslateBehavior extends ModelBehavior { * $config could be empty - and translations configured dynamically by * bindTranslation() method * + * By default INNER joins are used to fetch translations. In order to use + * other join types $config should contain 'join_type' key: + * ``` + * array( + * 'fields' => array('field_one', 'field_two' => 'FieldAssoc', 'field_three'), + * 'join_type' => 'LEFT', + * ) + * ``` + * In a model it may be configured this way: + * ``` + * public $actsAs = array( + * 'Translate' => array( + * 'content', + * 'title', + * 'join_type' => 'LEFT', + * ), + * ); + * ``` + * * @param Model $Model Model the behavior is being attached to. * @param array $config Array of configuration information. * @return mixed @@ -74,9 +93,16 @@ class TranslateBehavior extends ModelBehavior { return false; } - $this->settings[$Model->alias] = array(); + $this->settings[$Model->alias] = array( + 'fields' => array(), + 'join_type' => 'INNER', + ); $this->runtime[$Model->alias] = array('fields' => array()); $this->translateModel($Model); + if (isset($config['join_type'])) { + $this->settings[$Model->alias]['join_type'] = $config['join_type']; + unset($config['join_type']); + } return $this->bindTranslation($Model, $config, false); } @@ -124,7 +150,7 @@ class TranslateBehavior extends ModelBehavior { if (is_string($query['fields']) && $query['fields'] === "COUNT(*) AS {$db->name('count')}") { $query['fields'] = "COUNT(DISTINCT({$db->name($Model->escapeField())})) {$db->alias}count"; $query['joins'][] = array( - 'type' => 'INNER', + 'type' => $this->settings[$Model->alias]['join_type'], 'alias' => $RuntimeModel->alias, 'table' => $joinTable, 'conditions' => array( @@ -144,7 +170,7 @@ class TranslateBehavior extends ModelBehavior { } $fields = array_merge( - $this->settings[$Model->alias], + $this->settings[$Model->alias]['fields'], $this->runtime[$Model->alias]['fields'] ); $addFields = array(); @@ -200,7 +226,7 @@ class TranslateBehavior extends ModelBehavior { return $conditionFields; } foreach ($query['conditions'] as $col => $val) { - foreach ($this->settings[$Model->alias] as $field => $assoc) { + foreach ($this->settings[$Model->alias]['fields'] as $field => $assoc) { if (is_numeric($field)) { $field = $assoc; } @@ -254,7 +280,7 @@ class TranslateBehavior extends ModelBehavior { $query['fields'][] = $aliasVirtual; } $query['joins'][] = array( - 'type' => 'INNER', + 'type' => $this->settings[$Model->alias]['join_type'], 'alias' => $alias, 'table' => $joinTable, 'conditions' => array( @@ -374,7 +400,7 @@ class TranslateBehavior extends ModelBehavior { if (empty($locale)) { return true; } - $fields = array_merge($this->settings[$Model->alias], $this->runtime[$Model->alias]['fields']); + $fields = array_merge($this->settings[$Model->alias]['fields'], $this->runtime[$Model->alias]['fields']); $tempData = array(); foreach ($fields as $key => $value) { @@ -488,7 +514,7 @@ class TranslateBehavior extends ModelBehavior { * @return array The fully populated data to save. */ protected function _prepareTranslations(Model $Model, $data) { - $fields = array_merge($this->settings[$Model->alias], $this->runtime[$Model->alias]['fields']); + $fields = array_merge($this->settings[$Model->alias]['fields'], $this->runtime[$Model->alias]['fields']); $locales = array(); foreach ($data as $key => $value) { if (is_array($value)) { @@ -612,14 +638,14 @@ class TranslateBehavior extends ModelBehavior { if ($reset) { $this->runtime[$Model->alias]['fields'][] = $field; } else { - $this->settings[$Model->alias][] = $field; + $this->settings[$Model->alias]['fields'][] = $field; } } else { if ($reset) { $this->runtime[$Model->alias]['fields'][$field] = $association; $this->runtime[$Model->alias]['restoreFields'][] = $field; } else { - $this->settings[$Model->alias][$field] = $association; + $this->settings[$Model->alias]['fields'][$field] = $association; } foreach (array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany') as $type) { @@ -652,10 +678,10 @@ class TranslateBehavior extends ModelBehavior { * @return void */ protected function _removeField(Model $Model, $field) { - if (array_key_exists($field, $this->settings[$Model->alias])) { - unset($this->settings[$Model->alias][$field]); - } elseif (in_array($field, $this->settings[$Model->alias])) { - $this->settings[$Model->alias] = array_merge(array_diff($this->settings[$Model->alias], array($field))); + if (array_key_exists($field, $this->settings[$Model->alias]['fields'])) { + unset($this->settings[$Model->alias]['fields'][$field]); + } elseif (in_array($field, $this->settings[$Model->alias]['fields'])) { + $this->settings[$Model->alias]['fields'] = array_merge(array_diff($this->settings[$Model->alias]['fields'], array($field))); } if (array_key_exists($field, $this->runtime[$Model->alias]['fields'])) { @@ -675,11 +701,11 @@ class TranslateBehavior extends ModelBehavior { * @return bool */ public function unbindTranslation(Model $Model, $fields = null) { - if (empty($fields) && empty($this->settings[$Model->alias])) { + if (empty($fields) && empty($this->settings[$Model->alias]['fields'])) { return false; } if (empty($fields)) { - return $this->unbindTranslation($Model, $this->settings[$Model->alias]); + return $this->unbindTranslation($Model, $this->settings[$Model->alias]['fields']); } if (is_string($fields)) { diff --git a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php index 81737576a..8a572d661 100644 --- a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php +++ b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php @@ -528,6 +528,29 @@ class TranslateBehaviorTest extends CakeTestCase { $this->assertEquals($expected, $result); } + public function testMissingTranslationLeftJoin() { + $this->loadFixtures('Translate', 'TranslatedItem'); + $expected = array( + 'TranslatedItem' => Array ( + 'id' => '1', + 'translated_article_id' => '1', + 'slug' => 'first_translated', + 'locale' => 'rus', + 'content' => '', + 'title' => '', + ), + ); + + $TestModel = new TranslatedItemLeftJoin(); + $TestModel->locale = 'rus'; + $result = $TestModel->read(null, 1); + $this->assertEquals($expected, $result); + + $TestModel->locale = array('rus'); + $result = $TestModel->read(null, 1); + $this->assertEquals($expected, $result); + } + /** * testTranslatedFindList method * @@ -1376,15 +1399,15 @@ class TranslateBehaviorTest extends CakeTestCase { $Model->unbindTranslation(); $Model->bindTranslation(array('body', 'slug'), false); - $result = $Model->Behaviors->Translate->settings['TranslatedItem']; + $result = $Model->Behaviors->Translate->settings['TranslatedItem']['fields']; $this->assertEquals(array('body', 'slug'), $result); $Model->unbindTranslation(array('body')); - $result = $Model->Behaviors->Translate->settings['TranslatedItem']; + $result = $Model->Behaviors->Translate->settings['TranslatedItem']['fields']; $this->assertNotContains('body', $result); $Model->unbindTranslation('slug'); - $result = $Model->Behaviors->Translate->settings['TranslatedItem']; + $result = $Model->Behaviors->Translate->settings['TranslatedItem']['fields']; $this->assertNotContains('slug', $result); } diff --git a/lib/Cake/Test/Case/Model/models.php b/lib/Cake/Test/Case/Model/models.php index f42bcae35..f22132f1f 100644 --- a/lib/Cake/Test/Case/Model/models.php +++ b/lib/Cake/Test/Case/Model/models.php @@ -3247,6 +3247,17 @@ class TranslatedItem extends CakeTestModel { } +class TranslatedItemLeftJoin extends TranslatedItem { + + public $actsAs = array( + 'Translate' => array( + 'content', + 'title', + 'join_type' => 'LEFT', + ) + ); +} + /** * TranslatedItem class. *