Skip to content

Commit 0d3bad4

Browse files
committed
Relations refactor
1 parent ed6848f commit 0d3bad4

5 files changed

Lines changed: 171 additions & 135 deletions

File tree

src/Eloquent/Model.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
use PDPhilip\Elasticsearch\Data\ModelMeta;
99

1010
/**
11+
* @method bool|int push(string $column = null, mixed $values = null, bool $unique = false)
12+
*
1113
* @property object $searchHighlights
1214
* @property array $searchHighlightsAsArray
1315
* @property object $withHighlights

src/Relations/BelongsToMany.php

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,9 @@ public function attach($id, array $attributes = [], $touch = true)
7171
$query->push($this->foreignPivotKey, $this->parent->{$this->parentKey}, true);
7272
}
7373

74-
if ($this->isElasticParent()) {
75-
$this->parent->push($this->relatedPivotKey, (array) $id, true);
76-
} else {
77-
$this->addIdToParentRelationData($id);
78-
}
74+
$this->isElasticParent()
75+
? $this->parent->push($this->relatedPivotKey, (array) $id, true)
76+
: $this->addIdToParentRelationData($id);
7977

8078
if ($touch) {
8179
$this->touchIfTouching();
@@ -90,11 +88,9 @@ public function detach($ids = [], $touch = true)
9088

9189
$ids = (array) $ids;
9290

93-
if ($this->isElasticParent()) {
94-
$this->parent->pull($this->relatedPivotKey, $ids);
95-
} else {
96-
$this->removeIdsFromParentRelationData($ids);
97-
}
91+
$this->isElasticParent()
92+
? $this->parent->pull($this->relatedPivotKey, $ids)
93+
: $this->removeIdsFromParentRelationData($ids);
9894

9995
$query = $this->newRelatedQuery();
10096
if (count($ids) > 0) {

src/Relations/MorphToMany.php

Lines changed: 101 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,39 @@ public function addEagerConstraints(array $models)
2727
$ids = $this->getKeys($models, $this->table);
2828
$ids = $this->extractIds($ids[0] ?? []);
2929
$this->query->whereIn($this->relatedKey, $ids);
30-
} else {
31-
parent::addEagerConstraints($models);
32-
$this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass);
30+
31+
return;
3332
}
33+
34+
// Non-inverse: standard eager constraints with morph type filter
35+
parent::addEagerConstraints($models);
36+
$this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass);
3437
}
3538

3639
protected function setWhere()
3740
{
41+
if ($this->getInverse() && $this->isElasticParent()) {
42+
$ids = $this->extractIds((array) $this->parent->{$this->table});
43+
$this->query->whereIn($this->relatedKey, $ids);
44+
45+
return $this;
46+
}
47+
3848
if ($this->getInverse()) {
39-
if ($this->isElasticParent()) {
40-
$ids = $this->extractIds((array) $this->parent->{$this->table});
41-
$this->query->whereIn($this->relatedKey, $ids);
42-
} else {
43-
$this->query->whereIn($this->foreignPivotKey, (array) $this->parent->{$this->parentKey});
44-
}
45-
} else {
46-
if ($this->isElasticParent()) {
47-
$this->query->whereIn($this->relatedKey, (array) $this->parent->{$this->relatedPivotKey});
48-
} else {
49-
$this->query->whereIn($this->getQualifiedForeignPivotKeyName(), (array) $this->parent->{$this->parentKey});
50-
}
49+
$this->query->whereIn($this->foreignPivotKey, (array) $this->parent->{$this->parentKey});
50+
51+
return $this;
5152
}
5253

54+
if ($this->isElasticParent()) {
55+
$this->query->whereIn($this->relatedKey, (array) $this->parent->{$this->relatedPivotKey});
56+
57+
return $this;
58+
}
59+
60+
// SQL parent, non-inverse
61+
$this->query->whereIn($this->getQualifiedForeignPivotKeyName(), (array) $this->parent->{$this->parentKey});
62+
5363
return $this;
5464
}
5565

@@ -153,47 +163,47 @@ public function detach($ids = [], $touch = true)
153163
*/
154164
private function attachIdsToParent(array $ids): void
155165
{
156-
if ($this->getInverse()) {
157-
$morphClass = $this->related instanceof Model ? $this->related->getMorphClass() : null;
158-
159-
if ($this->isElasticParent()) {
160-
foreach ($ids as $id) {
161-
$this->parent->push($this->table, [
162-
$this->buildMorphEntry($this->relatedPivotKey, $id, $morphClass),
163-
], true);
164-
}
165-
} else {
166-
foreach ($ids as $id) {
167-
$this->addIdToParentRelationData($id);
168-
}
169-
}
170-
} else {
171-
if ($this->isElasticParent()) {
172-
$this->parent->push($this->relatedPivotKey, $ids, true);
173-
} else {
174-
foreach ($ids as $id) {
175-
$this->addIdToParentRelationData($id);
176-
}
166+
if (! $this->isElasticParent()) {
167+
foreach ($ids as $id) {
168+
$this->addIdToParentRelationData($id);
177169
}
170+
171+
return;
172+
}
173+
174+
if (! $this->getInverse()) {
175+
$this->parent->push($this->relatedPivotKey, $ids, true);
176+
177+
return;
178+
}
179+
180+
$morphClass = $this->related instanceof Model ? $this->related->getMorphClass() : null;
181+
foreach ($ids as $id) {
182+
$this->parent->push($this->table, [
183+
$this->buildMorphEntry($this->relatedPivotKey, $id, $morphClass),
184+
], true);
178185
}
179186
}
180187

181188
/**
182189
* Push parent reference onto a single related model instance.
183190
*
184-
* Inverse: related stores flat parent IDs in foreignPivotKey
191+
* Inverse: related stores flat parent IDs in foreignPivotKey
185192
* Non-inverse: related stores morph entries in $this->table
186193
*/
187194
private function attachParentToRelatedModel(Model $model): void
188195
{
189196
if ($this->getInverse()) {
190197
$model->push($this->foreignPivotKey, (array) $this->parent->{$this->parentKey}, true);
191-
} else {
192-
$morphClass = $this->parent instanceof Model ? $this->parent->getMorphClass() : null;
193-
$model->push($this->table, [
194-
$this->buildMorphEntry($this->foreignPivotKey, $this->parent->{$this->parentKey}, $morphClass),
195-
], true);
198+
199+
return;
196200
}
201+
202+
// Non-inverse: store morph entry on related
203+
$morphClass = $this->parent instanceof Model ? $this->parent->getMorphClass() : null;
204+
$model->push($this->table, [
205+
$this->buildMorphEntry($this->foreignPivotKey, $this->parent->{$this->parentKey}, $morphClass),
206+
], true);
197207
}
198208

199209
/**
@@ -205,12 +215,15 @@ private function attachParentToRelatedQuery($query): void
205215
{
206216
if ($this->getInverse()) {
207217
$query->push($this->foreignPivotKey, $this->parent->{$this->parentKey});
208-
} else {
209-
$morphClass = $this->parent instanceof Model ? $this->parent->getMorphClass() : null;
210-
$query->push($this->table, [
211-
$this->buildMorphEntry($this->foreignPivotKey, $this->parent->{$this->parentKey}, $morphClass),
212-
], true);
218+
219+
return;
213220
}
221+
222+
// Non-inverse: store morph entry on related
223+
$morphClass = $this->parent instanceof Model ? $this->parent->getMorphClass() : null;
224+
$query->push($this->table, [
225+
$this->buildMorphEntry($this->foreignPivotKey, $this->parent->{$this->parentKey}, $morphClass),
226+
], true);
214227
}
215228

216229
// ------------------------------------------------------------------
@@ -220,47 +233,51 @@ private function attachParentToRelatedQuery($query): void
220233
/**
221234
* Remove related IDs from the parent model.
222235
*
223-
* Inverse: removes morph entries from $this->table
236+
* Inverse: removes morph entries from $this->table
224237
* Non-inverse: removes flat IDs from $this->relatedPivotKey
225238
*/
226239
private function detachIdsFromParent(array $ids): void
227240
{
228-
if ($this->getInverse()) {
229-
$data = array_map(fn ($item) => $this->buildMorphEntry(
230-
$this->relatedPivotKey, $item, $this->related->getMorphClass()
231-
), $ids);
232-
233-
if ($this->isElasticParent()) {
234-
$this->parent->pull($this->table, $data);
235-
} else {
236-
$this->removeIdsFromParentRelationData($this->extractIds($data));
237-
}
238-
} else {
239-
if ($this->isElasticParent()) {
240-
$this->parent->pull($this->relatedPivotKey, $ids);
241-
} else {
242-
$this->removeIdsFromParentRelationData($ids);
243-
}
241+
if (! $this->getInverse()) {
242+
$this->isElasticParent()
243+
? $this->parent->pull($this->relatedPivotKey, $ids)
244+
: $this->removeIdsFromParentRelationData($ids);
245+
246+
return;
244247
}
248+
249+
$morphEntries = [];
250+
foreach ($ids as $id) {
251+
$morphEntries[] = $this->buildMorphEntry(
252+
$this->relatedPivotKey, $id, $this->related->getMorphClass()
253+
);
254+
}
255+
256+
$this->isElasticParent()
257+
? $this->parent->pull($this->table, $morphEntries)
258+
: $this->removeIdsFromParentRelationData($this->extractIds($morphEntries));
245259
}
246260

247261
/**
248262
* Remove parent reference from the related models.
249263
*
250-
* Inverse: removes flat parent ID from foreignPivotKey
264+
* Inverse: removes flat parent ID from foreignPivotKey
251265
* Non-inverse: removes morph entry from $this->table
252266
*/
253267
private function detachParentFromRelated($query): void
254268
{
255269
if ($this->getInverse()) {
256270
$query->pull($this->foreignPivotKey, $this->parent->{$this->parentKey});
257-
} else {
258-
$query->pull($this->table, [
259-
$this->buildMorphEntry(
260-
$this->foreignPivotKey, $this->parent->{$this->parentKey}, $this->parent->getMorphClass()
261-
),
262-
]);
271+
272+
return;
263273
}
274+
275+
// Non-inverse: remove morph entry from related
276+
$query->pull($this->table, [
277+
$this->buildMorphEntry(
278+
$this->foreignPivotKey, $this->parent->{$this->parentKey}, $this->parent->getMorphClass()
279+
),
280+
]);
264281
}
265282

266283
// ------------------------------------------------------------------
@@ -291,15 +308,12 @@ protected function buildDictionary(Collection $results)
291308
$dictionary = [];
292309

293310
foreach ($results as $result) {
294-
if ($this->getInverse()) {
295-
foreach ($result->$foreign as $item) {
296-
$dictionary[$item][] = $result;
297-
}
298-
} else {
299-
$items = $this->extractIds($result->{$this->table} ?? [], $foreign);
300-
foreach ($items as $item) {
301-
$dictionary[$item][] = $result;
302-
}
311+
$items = $this->getInverse()
312+
? $result->$foreign
313+
: $this->extractIds($result->{$this->table} ?? [], $foreign);
314+
315+
foreach ($items as $item) {
316+
$dictionary[$item][] = $result;
303317
}
304318
}
305319

@@ -308,14 +322,15 @@ protected function buildDictionary(Collection $results)
308322

309323
public function extractIds(array $data, ?string $relatedPivotKey = null)
310324
{
311-
$relatedPivotKey = $relatedPivotKey ?: $this->relatedPivotKey;
325+
$key = $relatedPivotKey ?: $this->relatedPivotKey;
326+
$ids = [];
312327

313-
return array_reduce($data, function ($carry, $item) use ($relatedPivotKey) {
314-
if (is_array($item) && array_key_exists($relatedPivotKey, $item)) {
315-
$carry[] = $item[$relatedPivotKey];
328+
foreach ($data as $item) {
329+
if (is_array($item) && array_key_exists($key, $item)) {
330+
$ids[] = $item[$key];
316331
}
332+
}
317333

318-
return $carry;
319-
}, []);
334+
return $ids;
320335
}
321336
}

src/Relations/Traits/InteractsWithPivotTable.php

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,44 @@
88

99
trait InteractsWithPivotTable
1010
{
11-
/** {@inheritdoc} */
11+
/**
12+
* Coerce all record keys to strings for ES consistency.
13+
*
14+
* {@inheritdoc}
15+
*/
1216
protected function formatRecordsList(array $records)
1317
{
14-
return collect($records)->mapWithKeys(function ($attributes, $id) {
18+
$formatted = [];
19+
20+
foreach ($records as $id => $attributes) {
1521
if (! is_array($attributes)) {
16-
[$id, $attributes] = [$attributes, []];
22+
$id = $attributes;
23+
$attributes = [];
1724
}
1825

1926
if ($id instanceof BackedEnum) {
2027
$id = $id->value;
2128
}
2229

23-
// We have to convert all Key Ids to string values to keep it consistent in Elastic.
24-
return [(string) $id => $attributes];
25-
})->all();
30+
$formatted[(string) $id] = $attributes;
31+
}
32+
33+
return $formatted;
2634
}
2735

28-
/** {@inheritdoc} */
36+
/**
37+
* Coerce all parsed IDs to strings for ES consistency.
38+
*
39+
* {@inheritdoc}
40+
*/
2941
protected function parseIds($value)
3042
{
31-
// We have to convert all Key Ids to string values to keep it consistent in Elastic.
32-
return collect(parent::parseIds($value))->mapWithKeys(function ($value, $key) {
33-
return [(string) $key => $value];
34-
})->all();
43+
$parsed = [];
44+
45+
foreach (parent::parseIds($value) as $key => $val) {
46+
$parsed[(string) $key] = $val;
47+
}
48+
49+
return $parsed;
3550
}
3651
}

0 commit comments

Comments
 (0)