Skip to content

Commit 5e8784d

Browse files
committed
Optimise reference filling
1 parent 12281c2 commit 5e8784d

File tree

2 files changed

+55
-26
lines changed

2 files changed

+55
-26
lines changed

src/Record.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@ public function __construct(Schema $schema)
3434

3535
public function getPrimaryKeys(): array
3636
{
37-
return array_intersect_key($this->values, array_flip($this->schema->getPrimaryKeys()));
37+
$primaryKey = [];
38+
39+
foreach ($this->schema->getPrimaryKeys() as $key) {
40+
$primaryKey[$key] = $this->values[$key];
41+
}
42+
43+
return $primaryKey;
3844
}
3945

4046
public function isNew(): bool
@@ -93,6 +99,11 @@ public function fillReference(string $name, array $records): void
9399
$this->relations[$name] = array_values($records);
94100
}
95101

102+
public function isReferenceLoaded(string $name): bool
103+
{
104+
return isset($this->relations[$name]);
105+
}
106+
96107
private function isRelated(Reference $relation, Record $record): bool
97108
{
98109
if ($relation->getReferencedSchema() !== $record->getSchema()) {

src/ReferenceFiller.php

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ public function fill(array $records, array $references): void
3939
throw new \InvalidArgumentException('The provided list of records did not share the same schema');
4040
}
4141

42-
$recordId = $this->getRecordId($schema, $record->getDatabaseValues());
43-
$this->cache[$schemaId][$recordId] = $record;
42+
$this->cacheRecord($schemaId, $record);
4443
}
4544

4645
$this->fillReferences($records, $references);
@@ -65,21 +64,43 @@ private function fillReferences(array $records, array $references): void
6564
throw new \RuntimeException('Filling references for composite foreign keys is not supported');
6665
}
6766

67+
$isPrimaryReference = $fields === $parent->getPrimaryKeys();
6868
$key = array_pop($keys);
6969
$field = array_pop($fields);
7070
$options = [];
71+
$sorted = [];
7172

7273
foreach ($records as $record) {
73-
$options[] = $record[$key];
74+
$value = $record[$key];
75+
76+
if ($record->isReferenceLoaded($name)) {
77+
$sorted[$value] = $record->getReference($name);
78+
79+
foreach ($sorted[$value] as $referencedRecord) {
80+
$this->cacheRecord($schemaId, $referencedRecord);
81+
}
82+
83+
continue;
84+
}
85+
86+
if ($isPrimaryReference && isset($this->cache[$schemaId][$value])) {
87+
$sorted[$value] = [$this->cache[$schemaId][$value]];
88+
continue;
89+
}
90+
91+
$options[$value] = true;
7492
}
7593

76-
$result = $this->connection->select($parent->getFields(), $parent->getTable(), [$field => $options]);
77-
$result->setFetchMode(\PDO::FETCH_ASSOC);
78-
$sorted = [];
94+
$options = array_keys(array_diff_key($options, $sorted));
7995

80-
foreach ($result as $row) {
81-
$record = $this->getCachedRecord($schemaId, $parent, $row);
82-
$sorted[$record[$field]][] = $record;
96+
if ($options) {
97+
$result = $this->connection->select($parent->getFields(), $parent->getTable(), [$field => $options]);
98+
$result->setFetchMode(\PDO::FETCH_ASSOC);
99+
100+
foreach ($result as $row) {
101+
$record = $this->getCachedRecord($schemaId, $parent, $row);
102+
$sorted[$record[$field]][] = $record;
103+
}
83104
}
84105

85106
foreach ($records as $record) {
@@ -111,9 +132,21 @@ private function parseReferences(array $references): array
111132
return $subReferences;
112133
}
113134

135+
private function cacheRecord(string $schemaId, Record $record): void
136+
{
137+
$recordId = implode('-', $record->getPrimaryKeys());
138+
$this->cache[$schemaId][$recordId] = $record;
139+
}
140+
114141
private function getCachedRecord(string $schemaId, Schema $schema, array $row): Record
115142
{
116-
$recordId = $this->getRecordId($schema, $row);
143+
$primaryKey = [];
144+
145+
foreach ($schema->getPrimaryKeys() as $key) {
146+
$primaryKey[] = $row[$key];
147+
}
148+
149+
$recordId = implode('-', $primaryKey);
117150

118151
if (isset($this->cache[$schemaId][$recordId])) {
119152
return $this->cache[$schemaId][$recordId];
@@ -128,19 +161,4 @@ private function getSchemaId(Schema $schema): string
128161
{
129162
return spl_object_hash($schema);
130163
}
131-
132-
private function getRecordId(Schema $schema, array $row)
133-
{
134-
$values = [];
135-
136-
foreach ($schema->getPrimaryKeys() as $key) {
137-
if (!isset($row[$key])) {
138-
throw new \RuntimeException('Cannot determine cache id for record');
139-
}
140-
141-
$values[] = $row[$key];
142-
}
143-
144-
return implode('-', $values);
145-
}
146164
}

0 commit comments

Comments
 (0)