Browse Source

Fix types not being used when marshalling composite keys via `_ids`.

Unlike for single keys that are being directly passed to the query as
conditions, composite keys are wrapped in a tuple comparison expression,
which requires the types to be explicitly defined, otherwise the values
are being bound with a type of `null`.
ndm2 4 years ago
parent
commit
437882c340
2 changed files with 48 additions and 1 deletions
  1. 6 1
      src/ORM/Marshaller.php
  2. 42 0
      tests/TestCase/ORM/MarshallerTest.php

+ 6 - 1
src/ORM/Marshaller.php

@@ -496,7 +496,12 @@ class Marshaller
             if (!is_array($first) || count($first) !== count($primaryKey)) {
                 return [];
             }
-            $filter = new TupleComparison($primaryKey, $ids, [], 'IN');
+            $type = [];
+            $schema = $target->getSchema();
+            foreach ((array)$target->getPrimaryKey() as $column) {
+                $type[] = $schema->getColumnType($column);
+            }
+            $filter = new TupleComparison($primaryKey, $ids, $type, 'IN');
         } else {
             $filter = [$primaryKey[0] . ' IN' => $ids];
         }

+ 42 - 0
tests/TestCase/ORM/MarshallerTest.php

@@ -3558,4 +3558,46 @@ class MarshallerTest extends TestCase
         ];
         $this->assertEquals($expected, $result->toArray());
     }
+
+    /**
+     * Tests that ID values are being bound with the correct type when loading associated records.
+     */
+    public function testInvalidTypesWhenLoadingAssociatedByIds()
+    {
+        $this->expectException(\InvalidArgumentException::class);
+        $this->expectExceptionMessage('Cannot convert value of type `string` to integer');
+
+        $data = [
+            'title' => 'article',
+            'body' => 'some content',
+            'comments' => [
+                '_ids' => ['foobar'],
+            ],
+        ];
+
+        $marshaller = new Marshaller($this->articles);
+        $marshaller->one($data, ['associated' => ['Comments']]);
+    }
+
+    /**
+     * Tests that composite ID values are being bound with the correct type when loading associated records.
+     */
+    public function testInvalidTypesWhenLoadingAssociatedByCompositeIds()
+    {
+        $this->expectException(\InvalidArgumentException::class);
+        $this->expectExceptionMessage('Cannot convert value of type `string` to integer');
+
+        $data = [
+            'title' => 'article',
+            'body' => 'some content',
+            'comments' => [
+                '_ids' => [['foo', 'bar']],
+            ],
+        ];
+
+        $this->articles->Comments->setPrimaryKey(['id', 'article_id']);
+
+        $marshaller = new Marshaller($this->articles);
+        $marshaller->one($data, ['associated' => ['Comments']]);
+    }
 }