Skip to content

Commit cbfd46a

Browse files
committed
feat: recursive nested relationships
1 parent 8f89e9d commit cbfd46a

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

src/Contracts/RelationsResolver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function relationForeignKeyFromRelationInstance(Relation $relationInstanc
2323

2424
public function relationLocalKeyFromRelationInstance(Relation $relationInstance): string;
2525

26-
public function guardRelationsForCollection(Collection $entities, array $requestedRelations, bool $normalized = false): Collection;
26+
public function guardRelationsForCollection(Collection $entities, array $requestedRelations, ?string $parentRelation = null, bool $normalized = false): Collection;
2727

28-
public function guardRelations(Model $entity, array $requestedRelations, bool $normalized = false);
28+
public function guardRelations(Model $entity, array $requestedRelations, ?string $parentRelation = null, bool $normalized = false);
2929
}

src/Drivers/Standard/RelationsResolver.php

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@ public function relationForeignKeyFromRelationInstance(Relation $relationInstanc
115115
{
116116
$laravelVersion = (float)app()->version();
117117

118-
return $laravelVersion > 5.7 || get_class($relationInstance) === HasOne::class ? $relationInstance->getQualifiedForeignKeyName() : $relationInstance->getQualifiedForeignKey();
118+
return $laravelVersion > 5.7 || get_class(
119+
$relationInstance
120+
) === HasOne::class ? $relationInstance->getQualifiedForeignKeyName(
121+
) : $relationInstance->getQualifiedForeignKey();
119122
}
120123

121124
/**
@@ -129,15 +132,12 @@ public function relationLocalKeyFromRelationInstance(Relation $relationInstance)
129132
switch (get_class($relationInstance)) {
130133
case HasOne::class:
131134
case MorphOne::class:
132-
return $relationInstance->getParent()->getTable().'.'.$relationInstance->getLocalKeyName();
133-
break;
135+
return $relationInstance->getParent()->getTable() . '.' . $relationInstance->getLocalKeyName();
134136
case BelongsTo::class:
135137
case MorphTo::class:
136138
return $relationInstance->getQualifiedOwnerKeyName();
137-
break;
138139
default:
139140
return $relationInstance->getQualifiedLocalKeyName();
140-
break;
141141
}
142142
}
143143

@@ -146,14 +146,19 @@ public function relationLocalKeyFromRelationInstance(Relation $relationInstance)
146146
*
147147
* @param Collection $entities
148148
* @param array $requestedRelations
149+
* @param string|null $parentRelation
149150
* @param bool $normalized
150151
* @return Collection
151152
*/
152-
public function guardRelationsForCollection(Collection $entities, array $requestedRelations, bool $normalized = false): Collection
153-
{
153+
public function guardRelationsForCollection(
154+
Collection $entities,
155+
array $requestedRelations,
156+
?string $parentRelation = null,
157+
bool $normalized = false
158+
): Collection {
154159
return $entities->transform(
155-
function ($entity) use ($requestedRelations, $normalized) {
156-
return $this->guardRelations($entity, $requestedRelations, $normalized);
160+
function ($entity) use ($requestedRelations, $parentRelation, $normalized) {
161+
return $this->guardRelations($entity, $requestedRelations, $parentRelation, $normalized);
157162
}
158163
);
159164
}
@@ -163,11 +168,16 @@ function ($entity) use ($requestedRelations, $normalized) {
163168
*
164169
* @param Model $entity
165170
* @param array $requestedRelations
171+
* @param string|null $parentRelation
166172
* @param bool $normalized
167173
* @return Model
168174
*/
169-
public function guardRelations(Model $entity, array $requestedRelations, bool $normalized = false): Model
170-
{
175+
public function guardRelations(
176+
Model $entity,
177+
array $requestedRelations,
178+
?string $parentRelation = null,
179+
bool $normalized = false
180+
): Model {
171181
if (!$normalized) {
172182
$requestedRelations = $this->normalizeRequestedRelations($requestedRelations);
173183
}
@@ -176,17 +186,27 @@ public function guardRelations(Model $entity, array $requestedRelations, bool $n
176186
ksort($relations);
177187

178188
foreach ($relations as $relationName => $relation) {
179-
if ($relationName === 'pivot') {
189+
if ($relationName === 'pivot' || $relationName === $parentRelation) {
180190
continue;
181191
}
182192

183193
if (!array_key_exists($relationName, $requestedRelations)) {
184194
unset($relations[$relationName]);
185195
} elseif ($relation !== null) {
186196
if ($relation instanceof Model) {
187-
$relation = $this->guardRelations($relation, $requestedRelations[$relationName], true);
197+
$relation = $this->guardRelations(
198+
$relation,
199+
$requestedRelations[$relationName],
200+
$relationName,
201+
true
202+
);
188203
} else {
189-
$relation = $this->guardRelationsForCollection($relation, $requestedRelations[$relationName], true);
204+
$relation = $this->guardRelationsForCollection(
205+
$relation,
206+
$requestedRelations[$relationName],
207+
$relationName,
208+
true
209+
);
190210
}
191211
}
192212
}

tests/Unit/Drivers/Standard/RelationsResolverTest.php

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

55
use Orion\Drivers\Standard\RelationsResolver;
66
use Orion\Http\Requests\Request;
7+
use Orion\Tests\Fixtures\App\Models\Category;
78
use Orion\Tests\Fixtures\App\Models\Company;
89
use Orion\Tests\Fixtures\App\Models\Post;
910
use Orion\Tests\Fixtures\App\Models\Team;
@@ -85,6 +86,35 @@ public function guarding_entity_nested_relations()
8586
{
8687
$post = new Post(['title' => 'test post']);
8788

89+
$parentCategory = new Category(['name' => 'parent category']); // categories
90+
$childCategory = new Category(['name' => 'child category']); // categories.categories
91+
$nestedChildCategory = new Category(['name' => 'nested child category']); // categories.categories.categories
92+
93+
$childCategory->setRelation('categories', collect([$nestedChildCategory]));
94+
$parentCategory->setRelation('categories', collect([$childCategory]));
95+
96+
$post->setRelations(
97+
[
98+
'categories' => collect([$parentCategory]),
99+
]
100+
);
101+
102+
$relationsResolver = new RelationsResolver(['categories'], []);
103+
$guardedPost = $relationsResolver->guardRelations($post, ['categories']);
104+
105+
self::assertArrayHasKey('categories', $guardedPost->getRelations());
106+
self::assertArrayHasKey('categories', $guardedPost->getRelation('categories')->first()->getRelations());
107+
self::assertArrayHasKey(
108+
'categories',
109+
$guardedPost->getRelation('categories')->first()->getRelation('categories')->first()->getRelations()
110+
);
111+
}
112+
113+
/** @test */
114+
public function guarding_entity_recursive_nested_relations()
115+
{
116+
$post = new Post(['title' => 'test post']);
117+
88118
$manager = new User(['name' => 'manager user']);
89119

90120
$team = new Team(['name' => 'test team']);
@@ -102,7 +132,10 @@ public function guarding_entity_nested_relations()
102132
);
103133

104134
$relationsResolver = new RelationsResolver(['user', 'editors.team.users', 'editors.team.company'], []);
105-
$guardedPost = $relationsResolver->guardRelations($post, ['user', 'editors.team.users', 'editors.team.company']);
135+
$guardedPost = $relationsResolver->guardRelations(
136+
$post,
137+
['user', 'editors.team.users', 'editors.team.company']
138+
);
106139

107140
self::assertArrayHasKey('user', $guardedPost->getRelations());
108141
self::assertArrayHasKey('editors', $guardedPost->getRelations());
@@ -159,4 +192,4 @@ public function resolving_deep_relation_from_param_constraint(): void
159192

160193
self::assertSame('user.posts', $relation);
161194
}
162-
}
195+
}

0 commit comments

Comments
 (0)