Browse Source

Re-implementing TranslateBehavior to use joins istead, this give
somewhat more freedom to the developer for modifying the query, for
example for sorting on a translated field

Jose Lorenzo Rodriguez 12 years ago
parent
commit
2e780bca91

+ 53 - 16
src/Model/Behavior/TranslateBehavior.php

@@ -19,6 +19,7 @@ use Cake\Event\Event;
 use Cake\ORM\Behavior;
 use Cake\ORM\Entity;
 use Cake\ORM\Table;
+use Cake\ORM\TableRegistry;
 
 class TranslateBehavior extends Behavior {
 
@@ -40,7 +41,8 @@ class TranslateBehavior extends Behavior {
  */
 	protected static $_defaultConfig = [
 		'implementedFinders' => [],
-		'implementedMethods' => ['locale' => 'locale']
+		'implementedMethods' => ['locale' => 'locale'],
+		'fields' => []
 	];
 
 /**
@@ -52,24 +54,53 @@ class TranslateBehavior extends Behavior {
 	public function __construct(Table $table, array $config = []) {
 		parent::__construct($table, $config);
 		$this->_table = $table;
+		$this->setupAssociations();
+	}
+
+	public function setupAssociations() {
+		$alias = $this->_table->alias();
+		foreach ($this->config()['fields'] as $field) {
+			$name = $field . '_translation';
+			$target = TableRegistry::get($name, [
+				'table' => 'i18n'
+			]);
 
-		$table->hasMany('I18n', [
-			'strategy' => 'subquery',
-			'foreignKey' => 'foreign_key',
-			'conditions' => ['I18n.model' => $table->alias()],
-			'propertyName' => '_i18n'
-		]);
+			$this->_table->hasOne($name, [
+				'targetTable' => $target,
+				'foreignKey' => 'foreign_key',
+				'joinType' => 'LEFT',
+				'conditions' => [
+					$name . '.model' => $alias,
+					$name . '.field' => $field,
+				],
+				'propertyName' => $field . '_translation'
+			]);
+		}
 	}
 
 	public function beforeFind(Event $event, $query) {
+		$fields = $this->config()['fields'];
+
+		if (empty($fields)) {
+			return;
+		}
+
 		$locale = (array)$this->locale();
-		$query->contain(['I18n' => function($q) use ($locale) {
-			if ($locale) {
-				$q->where(['I18n.locale IN' => $locale]);
-			}
+		if (!$locale) {
+			return;
+		}
 
+		$conditions = function($q) use ($locale) {
+			$q->where([$q->repository()->alias() . '.locale IN' => $locale]);
 			return $q;
-		}]);
+		};
+
+		$contain = [];
+		foreach ($fields as $field) {
+			$contain[$field . '_translation'] = $conditions;
+		}
+
+		$query->contain($contain);
 
 		if (count($locale) === 1) {
 			$locale = current($locale);
@@ -88,18 +119,24 @@ class TranslateBehavior extends Behavior {
 
 	protected function _rowMapper($results, $locale) {
 		return $results->map(function($row) use ($locale) {
-			$translations = (array)$row->get('_i18n');
 			$options = ['setter' => false, 'guard' => false];
 
-			foreach ($translations as $field) {
+			foreach ($this->config()['fields'] as $field) {
+				$name = $field . '_translation';
+				$translation = $row->get($name);
+
+				if (!$translation) {
+					continue;
+				}
+
 				$row->set([
-					$field->get('field') => $field->get('content'),
+					$field => $translation->get('content'),
 					'_locale' => $locale
 				], $options);
+				unset($row[$name]);
 			}
 
 			$row->clean();
-			unset($row['_i18n']);
 			return $row;
 		});
 	}

+ 3 - 2
tests/TestCase/Model/Behavior/TranslateBehaviorTest.php

@@ -42,7 +42,7 @@ class TranslateBehaviorTest extends TestCase {
  */
 	public function testFindSingleLocale() {
 		$table = TableRegistry::get('Articles');
-		$table->addBehavior('Translate');
+		$table->addBehavior('Translate', ['fields' => ['title', 'body']]);
 		$table->locale('eng');
 		$results = $table->find()->combine('title', 'body', 'id')->toArray();
 		$expected = [
@@ -62,9 +62,10 @@ class TranslateBehaviorTest extends TestCase {
 	public function testFindSingleLocaleWithConditions() {
 		$table = TableRegistry::get('Articles');
 		$table->addBehavior('Translate');
+		$table->addBehavior('Translate', ['fields' => ['title', 'body']]);
 		$table->locale('eng');
 		$results = $table->find()
-			->where(['id' => 2])
+			->where(['Articles.id' => 2])
 			->all();
 
 		$this->assertCount(1, $results);