diff --git a/src/Database/Dialect/TupleComparisonTranslatorTrait.php b/src/Database/Dialect/TupleComparisonTranslatorTrait.php index 96fdd8133bf..23ee53fa320 100644 --- a/src/Database/Dialect/TupleComparisonTranslatorTrait.php +++ b/src/Database/Dialect/TupleComparisonTranslatorTrait.php @@ -79,7 +79,7 @@ protected function _transformTupleComparison(TupleComparison $expression, $query foreach ($value as $tuple) { $surrogate->orWhere(function ($exp) use ($fields, $tuple) { - foreach ($tuple as $i => $value) { + foreach (array_values($tuple) as $i => $value) { $exp->add([$fields[$i] => $value]); } return $exp; diff --git a/src/ORM/Table.php b/src/ORM/Table.php index d99aac11792..2eff91cf7ca 100644 --- a/src/ORM/Table.php +++ b/src/ORM/Table.php @@ -2202,7 +2202,16 @@ public function loadInto($objects, array $contain) $query = $this ->find() ->where(function ($exp) use ($primaryKey, $keys) { - return $exp->in($this->aliasField($this->primaryKey()), $keys->toList()); + if (is_array($primaryKey) && count($primaryKey) === 1) { + $primaryKey = current($primaryKey); + } + + if (is_string($primaryKey)) { + return $exp->in($this->aliasField($primaryKey), $keys->toList()); + } + + $primaryKey = array_map([$this, 'aliasField'], $primaryKey); + return new \Cake\Database\Expression\TupleComparison($primaryKey, $keys->toList()); }) ->contain($contain); @@ -2216,8 +2225,13 @@ public function loadInto($objects, array $contain) ->toArray(); $contain = $query->contain(); - $results = $query->indexBy($primaryKey)->toArray(); $primaryKey = (array)$primaryKey; + $results = $query + ->indexBy(function ($e) use ($primaryKey) { + return implode(';', $e->extract($primaryKey)); + }) + ->toArray(); + $objects = $objects ->map(function ($object) use ($results, $contain, $properties, $primaryKey) { $key = implode(';', $object->extract($primaryKey)); diff --git a/tests/TestCase/ORM/CompositeKeysTest.php b/tests/TestCase/ORM/CompositeKeysTest.php index e5d123b7d79..da846b37f29 100644 --- a/tests/TestCase/ORM/CompositeKeysTest.php +++ b/tests/TestCase/ORM/CompositeKeysTest.php @@ -672,6 +672,52 @@ public function testFindThreadedCompositeKeys() $this->assertEquals($expected, $formatter($items)->toArray()); } + /** + * Tets that loadInto() is capable of handling composite primary keys + * + * @return void + */ + public function testLoadInto() + { + $table = TableRegistry::get('SiteAuthors'); + $tags = TableRegistry::get('SiteTags'); + $table->hasMany('SiteArticles', [ + 'foreignKey' => ['author_id', 'site_id'], + ]); + + $author = $table->get([1, 1]); + $result = $table->loadInto($author, ['SiteArticles']); + $this->assertSame($author, $result); + + $expected = $table->get([1, 1], ['contain' => ['SiteArticles']]); + $this->assertEquals($expected, $result); + } + + /** + * Tets that loadInto() is capable of handling composite primary keys + * when loading into multiple entities + * + * @return void + */ + public function testLoadIntoMany() + { + $table = TableRegistry::get('SiteAuthors'); + $tags = TableRegistry::get('SiteTags'); + $table->hasMany('SiteArticles', [ + 'foreignKey' => ['author_id', 'site_id'], + ]); + + $authors = $table->find()->toList(); + $result = $table->loadInto($authors, ['SiteArticles']); + + foreach ($authors as $k => $v) { + $this->assertSame($result[$k], $v); + } + + $expected = $table->find('all', ['contain' => ['SiteArticles']])->toList(); + $this->assertEquals($expected, $result); + } + /** * Helper method to skip tests when connection is SQLite. *