Skip to content

Commit 36fa6a5

Browse files
committed
Add more relationship test coverage
1 parent 3cbc0af commit 36fa6a5

File tree

6 files changed

+196
-19
lines changed

6 files changed

+196
-19
lines changed

src/Connection/MySqlConnection.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public function __construct(string $hostname, string $database, string $username
2020
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
2121
\PDO::ATTR_EMULATE_PREPARES => false,
2222
\PDO::MYSQL_ATTR_INIT_COMMAND => sprintf("SET time_zone = '%s'", date('P')),
23+
\PDO::MYSQL_ATTR_FOUND_ROWS => true,
2324
]);
2425
};
2526
}

src/Relationship.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ private function isReverseRelationship(Relationship $relationship): bool
124124
public function fillRelationship(array $records, array $referencedRecords): void
125125
{
126126
if (\count($this->getFields()) !== 1) {
127-
throw new \InvalidArgumentException('Relationship fill is not supported for composite foreign keys');
127+
throw new \RuntimeException('Relationship fill is not supported for composite foreign keys');
128128
}
129129

130130
if (empty($records)) {
@@ -181,7 +181,7 @@ private function assignSortedRecords(array $records, array $sorted): void
181181

182182
foreach ($records as $record) {
183183
if ($record->getSchema() !== $schema) {
184-
throw new \InvalidArgumentException('Quick fill can only fill referenced records for one schema');
184+
throw new \InvalidArgumentException('The filled records must all belong to the referencing schema');
185185
}
186186

187187
$value = $record[$field];

src/RelationshipFiller.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use Simply\Database\Connection\Connection;
66

77
/**
8-
* ReferenceFiller.
8+
* RelationshipFiller.
99
* @author Riikka Kalliomäki <[email protected]>
1010
* @copyright Copyright (c) 2018 Riikka Kalliomäki
1111
* @license http://opensource.org/licenses/mit-license.php MIT License
@@ -48,38 +48,43 @@ public function fill(array $records, array $relationships): void
4848

4949
/**
5050
* @param Record[] $records
51-
* @param string[] $references
51+
* @param string[] $relationships
5252
*/
53-
private function fillRelationships(array $records, array $references): void
53+
private function fillRelationships(array $records, array $relationships): void
5454
{
5555
$schema = reset($records)->getSchema();
5656

57-
foreach ($this->parseChildRelationships($references) as $name => $childRelationships) {
57+
foreach ($this->parseChildRelationships($relationships) as $name => $childRelationships) {
5858
$relationship = $schema->getRelationship($name);
5959
$keys = $relationship->getFields();
6060
$fields = $relationship->getReferencedFields();
6161
$parent = $relationship->getReferencedSchema();
6262
$schemaId = $this->getSchemaId($parent);
6363

6464
if (\count($fields) > 1) {
65-
throw new \RuntimeException('Filling references for composite foreign keys is not supported');
65+
throw new \RuntimeException('Filling relationships for composite foreign keys is not supported');
6666
}
6767

6868
$isPrimaryReference = $fields === $parent->getPrimaryKey();
6969
$key = array_pop($keys);
7070
$field = array_pop($fields);
71+
$fillRecords = [];
7172
$options = [];
7273
$filled = [];
7374

7475
foreach ($records as $record) {
7576
$value = $record[$key];
7677

77-
if ($record->hasReferencedRecords($name)) {
78+
if ($value === null) {
79+
$record->setReferencedRecords($name, []);
80+
} elseif ($record->hasReferencedRecords($name)) {
7881
$filled[$value] = $record->getReferencedRecords($name);
7982
} elseif ($isPrimaryReference && isset($this->cache[$schemaId][$value])) {
8083
$filled[$value] = [$this->cache[$schemaId][$value]];
81-
} elseif ($value !== null) {
84+
$fillRecords[] = $record;
85+
} else {
8286
$options[$value] = true;
87+
$fillRecords[] = $record;
8388
}
8489
}
8590

@@ -95,7 +100,7 @@ private function fillRelationships(array $records, array $references): void
95100
}
96101
}
97102

98-
$relationship->fillRelationship($records, $loaded);
103+
$relationship->fillRelationship($fillRecords, $loaded);
99104

100105
if ($loaded && $childRelationships) {
101106
$this->fillRelationships($loaded, $childRelationships);
@@ -127,7 +132,7 @@ private function cacheRecord(int $schemaId, Record $record): void
127132
$recordId = implode('-', $record->getPrimaryKey());
128133

129134
if (isset($this->cache[$schemaId][$recordId]) && $this->cache[$schemaId][$recordId] !== $record) {
130-
throw new \RuntimeException('Duplicated record detected when filling references for records');
135+
throw new \RuntimeException('Duplicated record detected when filling relationships for records');
131136
}
132137

133138
$this->cache[$schemaId][$recordId] = $record;

src/Schema.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
*/
1313
abstract class Schema
1414
{
15-
private $container;
16-
1715
/** @var string|Model */
1816
protected $model;
1917

@@ -27,10 +25,12 @@ abstract class Schema
2725

2826
private $relationshipCache;
2927

28+
private $container;
29+
3030
public function __construct(ContainerInterface $container)
3131
{
32-
$this->container = $container;
3332
$this->relationshipCache = [];
33+
$this->container = $container;
3434
}
3535

3636
public function getTable(): string
@@ -73,7 +73,7 @@ public function getRelationship(string $name): Relationship
7373
}
7474

7575
if (!isset($this->relationships[$name])) {
76-
throw new \InvalidArgumentException("Invalid reference '$name'");
76+
throw new \InvalidArgumentException("Invalid relationship '$name'");
7777
}
7878

7979
$this->relationshipCache[$name] = new Relationship(

tests/helpers/TestPersonSchema.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ class TestPersonSchema extends Schema
3636
'schema' => TestPersonSchema::class,
3737
'field' => 'id',
3838
],
39-
'spouse_alt' => [
39+
'spouse_reverse' => [
4040
'key' => 'id',
4141
'schema' => TestPersonSchema::class,
4242
'field' => 'spouse_id',
43+
'unique' => true,
4344
],
4445
'home' => [
4546
'key' => 'home_id',

tests/tests/SchemaTest.php

Lines changed: 173 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PHPUnit\Framework\TestCase;
66
use Simply\Container\Container;
7+
use Simply\Database\Test\TestHouseSchema;
78
use Simply\Database\Test\TestParentSchema;
89
use Simply\Database\Test\TestPersonSchema;
910

@@ -22,18 +23,19 @@ private function getPersonSchema(): TestPersonSchema
2223

2324
$container[TestPersonSchema::class] = $schema;
2425
$container[TestParentSchema::class] = new TestParentSchema($container);
26+
$container[TestHouseSchema::class] = new TestHouseSchema($container);
2527

2628
return $schema;
2729
}
28-
public function testInvalidRererence()
30+
public function testInvalidRelationship(): void
2931
{
3032
$schema = $this->getPersonSchema();
3133

3234
$this->expectException(\InvalidArgumentException::class);
33-
$schema->getRelationship('not-a-valid-reference');
35+
$schema->getRelationship('not-a-valid-relationship');
3436
}
3537

36-
public function testSchemaEquivalence()
38+
public function testSchemaEquivalence(): void
3739
{
3840
$schema = $this->getPersonSchema();
3941

@@ -69,4 +71,172 @@ public function testInvalidReferencedFields(): void
6971
$this->expectException(\InvalidArgumentException::class);
7072
new Relationship('test', $schema, ['id'], $schema, ['mother_id'], false);
7173
}
74+
75+
public function testMissingReverseRelationship(): void
76+
{
77+
$container = new Container();
78+
$schema = new class($container) extends Schema {
79+
protected $model = 'TestModel';
80+
protected $primaryKey = 'id';
81+
protected $fields = ['id', 'parent_id'];
82+
protected $table = 'test';
83+
protected $relationships = [
84+
'parent' => [
85+
'key' => 'parent_id',
86+
'schema' => 'TestSchema',
87+
'field' => 'id',
88+
],
89+
];
90+
};
91+
92+
$container['TestSchema'] = $schema;
93+
$relationship = $schema->getRelationship('parent');
94+
95+
$this->expectException(\RuntimeException::class);
96+
$relationship->getReverseRelationship();
97+
}
98+
99+
public function testMultipleReverseRelationships(): void
100+
{
101+
$container = new Container();
102+
$schema = new class($container) extends Schema {
103+
protected $model = 'TestModel';
104+
protected $primaryKey = 'id';
105+
protected $fields = ['id', 'parent_id'];
106+
protected $table = 'test';
107+
protected $relationships = [
108+
'parent' => [
109+
'key' => 'parent_id',
110+
'schema' => 'TestSchema',
111+
'field' => 'id',
112+
],
113+
'child' => [
114+
'key' => 'id',
115+
'schema' => 'TestSchema',
116+
'field' => 'parent_id',
117+
],
118+
'son' => [
119+
'key' => 'id',
120+
'schema' => 'TestSchema',
121+
'field' => 'parent_id',
122+
],
123+
];
124+
};
125+
126+
$container['TestSchema'] = $schema;
127+
$relationship = $schema->getRelationship('parent');
128+
129+
$this->expectException(\RuntimeException::class);
130+
$relationship->getReverseRelationship();
131+
}
132+
133+
public function testTryingToFillCompositeForeignKey(): void
134+
{
135+
$container = new Container();
136+
$schema = new class($container) extends Schema {
137+
protected $model = 'TestModel';
138+
protected $primaryKey = ['order_id', 'product_id'];
139+
protected $fields = ['order_id', 'product_id', 'replaced_order_id', 'replaced_product_id'];
140+
protected $table = 'test';
141+
protected $relationships = [
142+
'replacement' => [
143+
'key' => ['order_id', 'product_id'],
144+
'schema' => 'TestSchema',
145+
'field' => ['replaced_order_id', 'replaced_product_id'],
146+
],
147+
'replaced' => [
148+
'key' => ['replaced_order_id', 'replaced_product_id'],
149+
'schema' => 'TestSchema',
150+
'field' => ['order_id', 'product_id'],
151+
],
152+
];
153+
};
154+
155+
$container['TestSchema'] = $schema;
156+
$relationship = $schema->getRelationship('replaced');
157+
158+
$this->expectException(\RuntimeException::class);
159+
$relationship->fillRelationship([], []);
160+
}
161+
162+
public function testTryingToFillWrongReferringSchema(): void
163+
{
164+
$schema = $this->getPersonSchema();
165+
$relationship = $schema->getRelationship('home');
166+
167+
$house = new Record($relationship->getReferencedSchema());
168+
169+
$this->expectException(\InvalidArgumentException::class);
170+
$relationship->fillRelationship([$house], []);
171+
}
172+
173+
public function testTryingToFillWrongReferredSchema(): void
174+
{
175+
$schema = $this->getPersonSchema();
176+
$relationship = $schema->getRelationship('home');
177+
178+
$person = new Record($schema);
179+
$otherPerson = new Record($schema);
180+
181+
$this->expectException(\InvalidArgumentException::class);
182+
$relationship->fillRelationship([$person], [$otherPerson]);
183+
}
184+
185+
public function testTryFillingMultipleToUniqueRelationship(): void
186+
{
187+
$schema = $this->getPersonSchema();
188+
$relationship = $schema->getRelationship('spouse_reverse');
189+
190+
$person = new Record($schema);
191+
$person['id'] = 1;
192+
193+
$wife = new Record($schema);
194+
$wife['spouse_id'] = 1;
195+
196+
$husband = new Record($schema);
197+
$husband['spouse_id'] = 1;
198+
199+
$this->expectException(\InvalidArgumentException::class);
200+
$relationship->fillRelationship([$person], [$wife, $husband]);
201+
}
202+
203+
public function testTryFillingMultipleToPrimaryRelationship(): void
204+
{
205+
$schema = $this->getPersonSchema();
206+
$relationship = $schema->getRelationship('spouse');
207+
208+
$person = new Record($schema);
209+
$person['spouse_id'] = 1;
210+
211+
$wife = new Record($schema);
212+
$wife['id'] = 1;
213+
214+
$husband = new Record($schema);
215+
$husband['id'] = 1;
216+
217+
$this->expectException(\InvalidArgumentException::class);
218+
$relationship->fillRelationship([$person], [$wife, $husband]);
219+
}
220+
221+
public function testFillingWithNullValues(): void
222+
{
223+
$schema = $this->getPersonSchema();
224+
$relationship = $schema->getRelationship('spouse');
225+
226+
$personA = new Record($schema);
227+
$personA['id'] = 1;
228+
$personA['spouse_id'] = 2;
229+
230+
$personB = new Record($schema);
231+
$personB['id'] = 2;
232+
$personB['spouse_id'] = 1;
233+
234+
$personC = new Record($schema);
235+
236+
$relationship->fillRelationship([$personA, $personB, $personC], [$personA, $personB, $personC]);
237+
238+
$this->assertSame([$personB], $personA->getReferencedRecords('spouse'));
239+
$this->assertSame([$personA], $personB->getReferencedRecords('spouse'));
240+
$this->assertSame([], $personC->getReferencedRecords('spouse'));
241+
}
72242
}

0 commit comments

Comments
 (0)