Browse Source

Starting to implement select strategy for HasOne

Jose Lorenzo Rodriguez 12 years ago
parent
commit
10a501b5b1

+ 9 - 4
src/ORM/Association.php

@@ -72,6 +72,13 @@ abstract class Association {
 	const MANY_TO_MANY = 'manyToMany';
 
 /**
+ * Association type for many to one associations.
+ *
+ * @var string
+ */
+	const MANY_TO_ONE = 'manyToOne';
+
+/**
  * Name given to the association, it usually represents the alias
  * assigned to the target associated table
  *
@@ -455,11 +462,9 @@ abstract class Association {
 /**
  * Get the relationship type.
  *
- * @return string Constant of either ONE_TO_ONE, MANY_TO_ONE, or MANY_TO_MANY.
+ * @return string Constant of either ONE_TO_ONE, MANY_TO_ONE, ONE_TO_MANY or MANY_TO_MANY.
  */
-	public function type() {
-		return self::ONE_TO_ONE;
-	}
+	public abstract function type();
 
 /**
  * Proxies the finding operation to the target table's find method

+ 9 - 0
src/ORM/Association/BelongsTo.php

@@ -94,6 +94,15 @@ class BelongsTo extends Association {
 	}
 
 /**
+ * Get the relationship type.
+ *
+ * @return string
+ */
+	public function type() {
+		return self::MANY_TO_ONE;
+	}
+
+/**
  * {@inheritdoc}
  *
  */

+ 42 - 1
src/ORM/Association/HasOne.php

@@ -17,6 +17,7 @@ namespace Cake\ORM\Association;
 use Cake\Database\Expression\IdentifierExpression;
 use Cake\ORM\Association;
 use Cake\ORM\Association\DependentDeleteTrait;
+use Cake\ORM\Association\SelectableAssociationTrait;
 use Cake\ORM\Entity;
 use Cake\ORM\Table;
 use Cake\Utility\Inflector;
@@ -30,6 +31,7 @@ use Cake\Utility\Inflector;
 class HasOne extends Association {
 
 	use DependentDeleteTrait;
+	use SelectableAssociationTrait;
 
 /**
  * The type of join to be used when adding the association to a query
@@ -88,6 +90,15 @@ class HasOne extends Association {
 	}
 
 /**
+ * Get the relationship type.
+ *
+ * @return string
+ */
+	public function type() {
+		return self::ONE_TO_ONE;
+	}
+
+/**
  * Takes an entity from the source table and looks if there is a field
  * matching the property name for this association. The found entity will be
  * saved on the target table for this association by passing supplied
@@ -154,7 +165,37 @@ class HasOne extends Association {
  * {@inheritdoc}
  *
  */
-	public function eagerLoader(array $options) {
+	protected function _linkField($options) {
+		$links = [];
+		$name = $this->name();
+
+		foreach ((array)$options['foreignKey'] as $key) {
+			$links[] = sprintf('%s.%s', $name, $key);
+		}
+
+		if (count($links) === 1) {
+			return $links[0];
+		}
+
+		return $links;
+	}
+
+/**
+ * {@inheritdoc}
+ *
+ */
+	protected function _buildResultMap($fetchQuery, $options) {
+		$resultMap = [];
+		$key = (array)$this->target()->primaryKey();
+
+		foreach ($fetchQuery->all() as $result) {
+			$values = [];
+			foreach ($key as $k) {
+				$values[] = $result[$k];
+			}
+			$resultMap[implode(';', $values)] = $result;
+		}
+		return $resultMap;
 	}
 
 }

+ 2 - 2
src/ORM/Association/SelectableAssociationTrait.php

@@ -172,7 +172,7 @@ trait SelectableAssociationTrait {
 
 		$keys = (array)$query->repository()->primaryKey();
 
-		if ($this->type() === $this::ONE_TO_ONE) {
+		if ($this->type() === $this::MANY_TO_ONE) {
 			$keys = (array)$this->foreignKey();
 		}
 
@@ -203,7 +203,7 @@ trait SelectableAssociationTrait {
 	protected function _resultInjector($fetchQuery, $resultMap) {
 		$source = $this->source();
 		$sAlias = $source->alias();
-		$keys = $this->type() === $this::ONE_TO_ONE ?
+		$keys = $this->type() === $this::MANY_TO_ONE ?
 			$this->foreignKey() :
 			$source->primaryKey();
 

+ 1 - 1
src/ORM/EagerLoader.php

@@ -400,7 +400,7 @@ class EagerLoader {
 			}
 
 			$source = $meta['instance']->source();
-			$keys = $meta['instance']->type() === $meta['instance']::ONE_TO_ONE ?
+			$keys = $meta['instance']->type() === $meta['instance']::MANY_TO_ONE ?
 				(array)$meta['instance']->foreignKey() :
 				(array)$source->primaryKey();
 

+ 50 - 0
tests/TestCase/ORM/CompositeKeysTest.php

@@ -286,6 +286,56 @@ class CompositeKeyTest extends TestCase {
 	}
 
 /**
+ * Tests loding hasOne with composite keys
+ *
+ * @dataProvider internalStategiesProvider
+ * @return void
+ */
+	public function testHasOneEager($strategy) {
+		$strategy = 'select';
+		$table = TableRegistry::get('SiteAuthors');
+		$table->hasOne('SiteArticles', [
+			'propertyName' => 'first_article',
+			'strategy' => $strategy,
+			'foreignKey' => ['author_id', 'site_id']
+		]);
+		$query = new Query($this->connection, $table);
+		$results = $query->select()
+			->where(['SiteAuthors.id IN' => [1, 3]])
+			->contain('SiteArticles')
+			->hydrate(false)
+			->toArray();
+
+		$expected = [
+			[
+				'id' => 1,
+				'name' => 'mark',
+				'site_id' => 1,
+				'first_article' => [
+					'id' => 1,
+					'author_id' => 1,
+					'site_id' => 1,
+					'title' => 'First Article',
+					'body' => 'First Article Body'
+				]
+			],
+			[
+				'id' => 3,
+				'name' => 'jose',
+				'site_id' => 2,
+				'first_article' => [
+					'id' => 2,
+					'author_id' => 3,
+					'site_id' => 2,
+					'title' => 'Second Article',
+					'body' => 'Second Article Body'
+				]
+			]
+		];
+		$this->assertEquals($expected, $results);
+	}
+
+/**
  * Tests that it is possible to insert a new row using the save method
  * if the entity has composite primary key
  *