Skip to content

Commit

Permalink
Fix including deeply nested relationships
Browse files Browse the repository at this point in the history
  • Loading branch information
timacdonald committed Oct 12, 2023
1 parent 5ba3f16 commit e78b155
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 2 deletions.
23 changes: 21 additions & 2 deletions src/Concerns/Relationships.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ public static function guessRelationshipResourceUsing(callable|null $callback)
*/
public function withIncludePrefix(string $prefix)
{
$this->includePrefix = "{$this->includePrefix}{$prefix}.";
$this->includePrefix = self::joinIncludes($this->includePrefix, $prefix);

return $this;
}


/**
* @internal
*
Expand Down Expand Up @@ -117,7 +118,9 @@ private function resolveInclude(mixed $resource, string $prefix)
{
return match (true) {
$resource instanceof PotentiallyMissing && $resource->isMissing() => null,
$resource instanceof JsonApiResource || $resource instanceof JsonApiResourceCollection => $resource->withIncludePrefix($prefix),
$resource instanceof JsonApiResource || $resource instanceof JsonApiResourceCollection => $resource->withIncludePrefix(
self::joinIncludes($this->includePrefix, $prefix)
),
default => throw UnknownRelationshipException::from($resource),
};
}
Expand Down Expand Up @@ -198,4 +201,20 @@ private static function guessRelationshipResource(string $relationship, JsonApiR
throw new RuntimeException('Unable to guess the resource class for relationship ['.$value.'] for ['.$resource::class.'].');
})($relationship, $resource);
}

/**
* @internal
*/
private static function joinIncludes(string $start, string $finish): string
{
$prefix = '';

if ($start !== '') {
$prefix = Str::finish($start, '.');
}

$prefix .= Str::finish($finish, '.');

return $prefix;
}
}
151 changes: 151 additions & 0 deletions tests/Feature/RelationshipsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1401,4 +1401,155 @@ public function toRelationships($request): array
]);
$this->assertValidJsonApi($response);
}

public function testItCanIncludeDeepNestedResourcesForASingleResource(): void
{
$post = new BasicModel([
'id' => 'post-id',
'title' => 'post-title',
'content' => 'post-content',
]);
$post->author = new BasicModel([
'id' => 'author-id',
'name' => 'author-name',
]);
$post->author->license = new BasicModel([
'id' => 'license-id',
'key' => 'license-key',
]);
$post->author->license->user = new BasicModel([
'id' => 'user-id',
'name' => 'Average Joe',
]);
$post->author->license->user->posts = Collection::make([
new BasicModel([
'id' => 'nested-post-id',
'title' => 'Hello world!',
]),
]);
$post->author->license->user->posts[0]->author = new BasicModel([
'id' => 'nested-post-author-id',
'name' => 'Tim Mac',
]);
$post->author->license->user->posts[0]->comments = Collection::make([
new BasicModel([
'id' => 'nested-post-comment-id',
'content' => 'Oh hey there!',
]),
]);
Route::get('test-route', fn () => PostResource::make($post));

$response = $this->getJson('test-route?include=author.license.user.posts.comments,author.license.user.posts.author');

$response->assertOk();
$response->assertExactJson([
'data' => [
'id' => 'post-id',
'type' => 'basicModels',
'attributes' => [
'title' => 'post-title',
'content' => 'post-content',
],
'relationships' => [
'author' => [
'data' => [
'id' => 'author-id',
'type' => 'basicModels',
],
],
],
],
'jsonapi' => [
'version' => '1.0',
],
'included' => [
[
'id' => 'author-id',
'type' => 'basicModels',
'attributes' => [
'name' => 'author-name',
],
'relationships' => [
'license' => [
'data' => [
'id' => 'license-id',
'type' => 'basicModels',
],
],
],
],
[
'id' => 'license-id',
'type' => 'basicModels',
'attributes' => [
'key' => 'license-key',
],
'relationships' => [
'user' => [
'data' => [
'id' => 'user-id',
'type' => 'basicModels',
],
],
],
],
[
'id' => 'user-id',
'type' => 'basicModels',
'attributes' => [
'name' => 'Average Joe',
],
'relationships' => [
'posts' => [
'data' => [
[
'id' => 'nested-post-id',
'type' => 'basicModels',
]
]
]
]
],
[
'id' => 'nested-post-id',
'type' => 'basicModels',
'attributes' => [
'title' => 'Hello world!',
'content' => null,
],
'relationships' => [
'author' => [
'data' => [
'id' => 'nested-post-author-id',
'type' => 'basicModels',
]
],
'comments' => [
'data' => [
[
'id' => 'nested-post-comment-id',
'type' => 'basicModels',
]
]
]
]
],
[
'id' => 'nested-post-author-id',
'type' => 'basicModels',
'attributes' => [
'name' => 'Tim Mac',
],
],
[
'id' => 'nested-post-comment-id',
'type' => 'basicModels',
'attributes' => [
'content' => 'Oh hey there!',
],
]
],
]);
$this->assertValidJsonApi($response);
}
}

0 comments on commit e78b155

Please sign in to comment.