Skip to content

Commit 6caa48b

Browse files
committed
Finish relationship renaming
1 parent e58e15d commit 6caa48b

File tree

9 files changed

+175
-152
lines changed

9 files changed

+175
-152
lines changed

src/Record.php

Lines changed: 50 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Record implements \ArrayAccess
2525
private $state;
2626

2727
/** @var Record[][] */
28-
private $references;
28+
private $referencedRecords;
2929

3030
private $model;
3131

@@ -35,7 +35,7 @@ public function __construct(Schema $schema)
3535
$this->values = array_fill_keys($schema->getFields(), null);
3636
$this->state = self::STATE_INSERT;
3737
$this->changed = [];
38-
$this->references = [];
38+
$this->referencedRecords = [];
3939
}
4040

4141
public function getPrimaryKey(): array
@@ -88,12 +88,43 @@ public function getModel(): Model
8888
return $this->model;
8989
}
9090

91-
public function getReferencedModel(string $name): Model
91+
public function hasReferencedRecords(string $name): bool
92+
{
93+
$name = $this->getSchema()->getRelationship($name)->getName();
94+
95+
return isset($this->referencedRecords[$name]);
96+
}
97+
98+
public function setReferencedRecords(string $name, array $records): void
99+
{
100+
$name = $this->getSchema()->getRelationship($name)->getName();
101+
102+
(function (Record ... $records) use ($name): void {
103+
$this->referencedRecords[$name] = $records;
104+
})(... $records);
105+
}
106+
107+
/**
108+
* @param string $name
109+
* @return Record[]
110+
*/
111+
public function getReferencedRecords(string $name): array
112+
{
113+
$name = $this->getSchema()->getRelationship($name)->getName();
114+
115+
if (!isset($this->referencedRecords[$name])) {
116+
throw new \RuntimeException("The referenced records for the relationship '$name' have not been provided");
117+
}
118+
119+
return $this->referencedRecords[$name];
120+
}
121+
122+
public function getRelatedModel(string $name): ?Model
92123
{
93124
$relationship = $this->getSchema()->getRelationship($name);
94125

95126
if (!$relationship->isUniqueRelationship()) {
96-
throw new \RuntimeException('Cannot fetch a single model a non-unique relationship');
127+
throw new \RuntimeException('A single related model can only be fetched for an unique relationship');
97128
}
98129

99130
$records = $this->getReferencedRecords($name);
@@ -105,12 +136,12 @@ public function getReferencedModel(string $name): Model
105136
return $this->getReferencedRecords($name)[0]->getModel();
106137
}
107138

108-
public function getReferredModels(string $name): array
139+
public function getRelatedModels(string $name): array
109140
{
110-
$reference = $this->getSchema()->getRelationship($name);
141+
$relationship = $this->getSchema()->getRelationship($name);
111142

112-
if ($reference->isUniqueRelationship()) {
113-
throw new \RuntimeException('Cannot refer to multiple models in a single relationship');
143+
if ($relationship->isUniqueRelationship()) {
144+
throw new \RuntimeException('Cannot fetch multiple models for an unique relationship');
114145
}
115146

116147
$models = [];
@@ -122,17 +153,17 @@ public function getReferredModels(string $name): array
122153
return $models;
123154
}
124155

125-
public function getReferredProxyModels(string $proxy, string $name): array
156+
public function getRelatedModelsByProxy(string $proxy, string $name): array
126157
{
127-
$proxyReference = $this->getSchema()->getRelationship($proxy);
128-
$reference = $proxyReference->getReferencedSchema()->getRelationship($name);
158+
$proxyRelationship = $this->getSchema()->getRelationship($proxy);
159+
$relationship = $proxyRelationship->getReferencedSchema()->getRelationship($name);
129160

130-
if ($proxyReference->isUniqueRelationship()) {
131-
throw new \RuntimeException('Cannot refer to multiple models in a single relationship');
161+
if ($proxyRelationship->isUniqueRelationship()) {
162+
throw new \RuntimeException('Cannot fetch related models via an unique proxy relationship');
132163
}
133164

134-
if (!$reference->isUniqueRelationship()) {
135-
throw new \RuntimeException('Can only refer to single models in a single relationship');
165+
if (!$relationship->isUniqueRelationship()) {
166+
throw new \RuntimeException('Related models can only be fetched via proxy with an unique relationship');
136167
}
137168

138169
$models = [];
@@ -141,7 +172,7 @@ public function getReferredProxyModels(string $proxy, string $name): array
141172
$records = $record->getReferencedRecords($name);
142173

143174
if (empty($records)) {
144-
throw new \UnexpectedValueException('The single relationship does not refer to any record');
175+
continue;
145176
}
146177

147178
$models[] = $records[0]->getModel();
@@ -150,82 +181,17 @@ public function getReferredProxyModels(string $proxy, string $name): array
150181
return $models;
151182
}
152183

153-
public function hasReferencedRecords(string $name): bool
154-
{
155-
return isset($this->references[$name]);
156-
}
157-
158-
/**
159-
* @param string $name
160-
* @return Record[]
161-
*/
162-
public function getReferencedRecords(string $name): array
163-
{
164-
if (!isset($this->references[$name])) {
165-
throw new \RuntimeException("The referenced records for the relationship '$name' have not been filled");
166-
}
167-
168-
return $this->references[$name];
169-
}
170-
171-
/**
172-
* @param string $name
173-
* @param Record[] $records
174-
*/
175-
public function fillReferencedRecords(string $name, array $records): void
176-
{
177-
$relationship = $this->getSchema()->getRelationship($name);
178-
179-
if (\count($records) > 1 && $relationship->isUniqueRelationship()) {
180-
throw new \InvalidArgumentException('A unique relationship cannot reference more than a single record');
181-
}
182-
183-
foreach ($records as $record) {
184-
if (!$this->isRelated($relationship, $record)) {
185-
throw new \InvalidArgumentException('The provided records are not related to this record');
186-
}
187-
}
188-
189-
if ($relationship->getReverseRelationship()->isUniqueRelationship()) {
190-
$reverse = $relationship->getReverseRelationship()->getName();
191-
192-
foreach ($records as $record) {
193-
$record->references[$reverse] = [$this];
194-
}
195-
}
196-
197-
$this->references[$name] = array_values($records);
198-
}
199-
200-
private function isRelated(Relationship $reference, Record $record): bool
201-
{
202-
if ($reference->getReferencedSchema() !== $record->getSchema()) {
203-
return false;
204-
}
205-
206-
$keys = $reference->getFields();
207-
$fields = $reference->getReferencedFields();
208-
209-
foreach ($keys as $index => $key) {
210-
if ((string) $this->values[$key] !== (string) $record->values[$fields[$index]]) {
211-
return false;
212-
}
213-
}
214-
215-
return true;
216-
}
217-
218184
/**
219185
* @return Record[]
220186
*/
221-
public function getMappedRecords(): array
187+
public function getAllReferencedRecords(): array
222188
{
223189
/** @var Record[] $records */
224190
$records = [spl_object_id($this) => $this];
225191

226192
do {
227-
foreach (current($records)->references as $relation) {
228-
foreach ($relation as $record) {
193+
foreach (current($records)->referencedRecords as $recordList) {
194+
foreach ($recordList as $record) {
229195
$id = spl_object_id($record);
230196

231197
if (!isset($records[$id])) {
@@ -288,6 +254,4 @@ public function offsetUnset($offset)
288254
{
289255
$this->offsetSet($offset, null);
290256
}
291-
292-
293257
}

src/Relationship.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,83 @@ private function isReverseRelationship(Relationship $relationship): bool
116116
&& $relationship->getFields() === $this->getReferencedFields()
117117
&& $relationship->getReferencedFields() === $this->getFields();
118118
}
119+
120+
/**
121+
* @param Record[] $records
122+
* @param Record[] $referencedRecords
123+
*/
124+
public function fillRelationship(array $records, array $referencedRecords): void
125+
{
126+
if (\count($this->getFields()) !== 1) {
127+
throw new \InvalidArgumentException('Relationship fill is not supported for composite foreign keys');
128+
}
129+
130+
if (empty($records)) {
131+
return;
132+
}
133+
134+
$this->assignSortedRecords($records, $this->getSortedRecords($referencedRecords));
135+
}
136+
137+
/**
138+
* @param Record[] $records
139+
* @return Record[][]
140+
*/
141+
private function getSortedRecords(array $records): array
142+
{
143+
$schema = $this->getReferencedSchema();
144+
$field = $this->getReferencedFields()[0];
145+
$unique = $this->isUniqueRelationship();
146+
$sorted = [];
147+
148+
foreach ($records as $record) {
149+
if ($record->getSchema() !== $schema) {
150+
throw new \InvalidArgumentException('The referenced records must all belong to the referenced schema');
151+
}
152+
153+
$value = $record[$field];
154+
155+
if ($value === null) {
156+
continue;
157+
}
158+
159+
if ($unique && isset($sorted[$value])) {
160+
throw new \InvalidArgumentException('Unique relationship cannot reference more than a single record');
161+
}
162+
163+
$sorted[$value][] = $record;
164+
}
165+
166+
return $sorted;
167+
}
168+
169+
/**
170+
* @param Record[] $records
171+
* @param Record[][] $sorted
172+
*/
173+
private function assignSortedRecords(array $records, array $sorted): void
174+
{
175+
$schema = $this->getSchema();
176+
$name = $this->getName();
177+
$field = $this->getFields()[0];
178+
179+
$fillReverse = $this->getReverseRelationship()->isUniqueRelationship();
180+
$reverse = $this->getReverseRelationship()->getName();
181+
182+
foreach ($records as $record) {
183+
if ($record->getSchema() !== $schema) {
184+
throw new \InvalidArgumentException('Quick fill can only fill referenced records for one schema');
185+
}
186+
187+
$value = $record[$field];
188+
$sortedRecords = $value === null || empty($sorted[$value]) ? [] : $sorted[$value];
189+
$record->setReferencedRecords($name, $sortedRecords);
190+
191+
if ($fillReverse) {
192+
foreach ($sortedRecords as $reverseRecord) {
193+
$reverseRecord->setReferencedRecords($reverse, [$record]);
194+
}
195+
}
196+
}
197+
}
119198
}

0 commit comments

Comments
 (0)