Skip to content

Commit 4ea19c1

Browse files
authored
fix: Resolve nested relations (#66)
1 parent d4b9e01 commit 4ea19c1

File tree

2 files changed

+134
-11
lines changed

2 files changed

+134
-11
lines changed

src/Resolver/StoryResolver.php

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,30 @@ public function resolve(array $target, array $relations): array
3131
$relationMap[$relation['uuid']] = $relation;
3232
}
3333

34-
foreach ($target as &$value) {
35-
if (\is_string($value) && \array_key_exists($value, $relationMap)) {
36-
$value = $relationMap[$value];
3734

38-
continue;
39-
}
35+
// Resolve relations within the relation map first
36+
$this->doResolve($relationMap, $relationMap);
4037

41-
if (\is_array($value) && \array_key_exists('id', $value) && \array_key_exists($value['id'], $relationMap)) {
42-
$value = $relationMap[$value['id']];
38+
// Then resolve relations in the main target
39+
$this->doResolve($target, $relationMap);
40+
41+
return $target;
42+
}
4343

44+
private function doResolve(array &$target, array &$relationMap): void
45+
{
46+
foreach ($target as $key => &$value) {
47+
if ('uuid' === $key) {
4448
continue;
4549
}
4650

47-
if (\is_array($value)) {
48-
$value = $this->resolve($value, $relations);
51+
if (\is_string($value) && isset($relationMap[$value])) {
52+
$value = $relationMap[$value];
53+
} elseif (\is_array($value) && isset($value['id'], $relationMap[$value['id']])) {
54+
$value = $relationMap[$value['id']];
55+
} elseif (\is_array($value)) {
56+
$this->doResolve($value, $relationMap);
4957
}
5058
}
51-
52-
return $target;
5359
}
5460
}

tests/Unit/Resolver/StoryResolverTest.php

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,121 @@ public function resolveReplacesMultiLinkWithLinkPayload(): void
188188

189189
self::assertSame($expected, $resolver->resolve($story, $references));
190190
}
191+
192+
#[Test]
193+
public function resolveRecursive(): void
194+
{
195+
$resolver = new StoryResolver();
196+
197+
$faker = self::faker();
198+
199+
$story = [
200+
'name' => $faker->word(),
201+
'content' => [
202+
'uuid' => $faker->uuid(),
203+
'reference' => $cUuid = $faker->uuid(),
204+
'some_field' => $faker->word(),
205+
],
206+
];
207+
208+
$references = [
209+
$b = [
210+
'uuid' => $bUuid = $faker->uuid(),
211+
'name' => $faker->word(),
212+
'another_field' => $faker->sentence(),
213+
],
214+
$c = [
215+
'uuid' => $cUuid,
216+
'name' => $faker->word(),
217+
'some_field' => [
218+
'test' => $bUuid,
219+
],
220+
],
221+
];
222+
223+
$expected = $story;
224+
$expected['content']['reference'] = $c;
225+
$expected['content']['reference']['some_field']['test'] = $b;
226+
227+
self::assertSame($expected, $resolver->resolve($story, $references));
228+
}
229+
230+
#[Test]
231+
public function resolveWithManyNestedRels(): void
232+
{
233+
$resolver = new StoryResolver();
234+
235+
$faker = self::faker();
236+
237+
$story = [
238+
'name' => $faker->word(),
239+
'content' => [
240+
'uuid' => $faker->uuid(),
241+
'reference' => $cUuid = $faker->uuid(),
242+
'some_field' => $faker->word(),
243+
],
244+
];
245+
246+
$references = [
247+
$a = [
248+
'uuid' => $aUuid = $faker->uuid(),
249+
'name' => $faker->word(),
250+
],
251+
$b = [
252+
'uuid' => $bUuid = $faker->uuid(),
253+
'name' => $faker->word(),
254+
'another_field' => $faker->sentence(),
255+
'field' => $aUuid,
256+
],
257+
$c = [
258+
'uuid' => $cUuid,
259+
'name' => $faker->word(),
260+
'some_field' => [
261+
'test' => $bUuid,
262+
],
263+
],
264+
];
265+
266+
$expected = $story;
267+
$expected['content']['reference'] = $c;
268+
$expected['content']['reference']['some_field']['test'] = $b;
269+
$expected['content']['reference']['some_field']['test']['field'] = $a;
270+
271+
self::assertSame($expected, $resolver->resolve($story, $references));
272+
}
273+
274+
#[Test]
275+
public function resolveMustNeverResolveUuidOfStory(): void
276+
{
277+
$resolver = new StoryResolver();
278+
279+
$faker = self::faker();
280+
281+
$story = [
282+
'name' => $faker->word(),
283+
'content' => [
284+
'uuid' => $uuid = $faker->uuid(),
285+
'reference' => $referenceUuid = $faker->uuid(),
286+
'some_field' => $faker->word(),
287+
],
288+
];
289+
290+
$references = [
291+
$a = [
292+
'uuid' => $referenceUuid,
293+
'name' => $faker->word(),
294+
'another_field' => $faker->sentence(),
295+
],
296+
$b = [
297+
'uuid' => $uuid,
298+
'name' => $faker->word(),
299+
'another_field' => $faker->sentence(),
300+
],
301+
];
302+
303+
$expected = $story;
304+
$expected['content']['reference'] = $a;
305+
306+
self::assertSame($expected, $resolver->resolve($story, $references));
307+
}
191308
}

0 commit comments

Comments
 (0)