Skip to content

Commit b13c5b3

Browse files
committed
Implement a 'Deferred type loader' example
Introducing an `AuthorTypeLoader`, to be used in `BlogType`. Note: The (SQLite) repository implementation to get all authors is simple, focus for this example application is showcasing the GraphQL framework.
1 parent 1b9d7bc commit b13c5b3

File tree

4 files changed

+95
-8
lines changed

4 files changed

+95
-8
lines changed

src/Domain/Author/AuthorRepository.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,10 @@ interface AuthorRepository
1313
{
1414
public function getById(string $authorId): Author;
1515

16+
/**
17+
* @return list<Author>
18+
*/
19+
public function getByIds(string ...$authorIds): array;
20+
1621
public function save(Author $author): void;
1722
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jerowork\ExampleApplicationGraphqlAttributeSchema\Infrastructure\Api\Http\GraphQL\Loader;
6+
7+
use Jerowork\ExampleApplicationGraphqlAttributeSchema\Domain\Author\AuthorRepository;
8+
use Jerowork\ExampleApplicationGraphqlAttributeSchema\Infrastructure\Api\Http\GraphQL\Type\AuthorType;
9+
use Jerowork\GraphqlAttributeSchema\Type\Loader\DeferredType;
10+
use Jerowork\GraphqlAttributeSchema\Type\Loader\DeferredTypeLoader;
11+
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
12+
13+
#[Autoconfigure(public: true)]
14+
final readonly class AuthorTypeLoader implements DeferredTypeLoader
15+
{
16+
public function __construct(
17+
private AuthorRepository $authorRepository,
18+
) {}
19+
20+
/**
21+
* @param list<string> $references
22+
*/
23+
public function load(array $references): array
24+
{
25+
return array_map(
26+
fn($author) => new DeferredType($author->id, new AuthorType($author)),
27+
$this->authorRepository->getByIds(...$references),
28+
);
29+
}
30+
}

src/Infrastructure/Api/Http/GraphQL/Type/BlogType.php

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
namespace Jerowork\ExampleApplicationGraphqlAttributeSchema\Infrastructure\Api\Http\GraphQL\Type;
66

77
use DateTimeImmutable;
8-
use Jerowork\ExampleApplicationGraphqlAttributeSchema\Domain\Author\AuthorRepository;
98
use Jerowork\ExampleApplicationGraphqlAttributeSchema\Domain\Blog\Blog;
10-
use Jerowork\GraphqlAttributeSchema\Attribute\Autowire;
9+
use Jerowork\ExampleApplicationGraphqlAttributeSchema\Infrastructure\Api\Http\GraphQL\Loader\AuthorTypeLoader;
1110
use Jerowork\GraphqlAttributeSchema\Attribute\Cursor;
1211
use Jerowork\GraphqlAttributeSchema\Attribute\Field;
1312
use Jerowork\GraphqlAttributeSchema\Attribute\Option\ListType;
@@ -42,12 +41,10 @@ public function getTitle(): string
4241
return $this->blog->title;
4342
}
4443

45-
#[Field]
46-
public function getAuthor(
47-
#[Autowire]
48-
AuthorRepository $authorRepository,
49-
): AuthorType {
50-
return new AuthorType($authorRepository->getById($this->blog->authorId));
44+
#[Field(type: AuthorType::class, deferredTypeLoader: AuthorTypeLoader::class)]
45+
public function getAuthor(): string
46+
{
47+
return $this->blog->authorId;
5148
}
5249

5350
/**

src/Infrastructure/Persistence/Author/SQLite/SQLiteAuthorRepository.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,61 @@ public function getById(string $authorId): Author
6161
);
6262
}
6363

64+
public function getByIds(string ...$authorIds): array
65+
{
66+
$sqlite = $this->sqliteFactory->create();
67+
68+
$idBinds = [];
69+
for ($i = 0; $i < count($authorIds); ++$i) {
70+
$idBinds[] = sprintf(':id_%d', $i);
71+
}
72+
73+
$idBinds = implode(', ', $idBinds);
74+
75+
$statement = $sqlite->prepare(
76+
<<<SQL
77+
SELECT *
78+
FROM author
79+
WHERE id IN({$idBinds})
80+
SQL
81+
);
82+
83+
if ($statement === false) {
84+
throw new RuntimeException('Failed to prepare statement');
85+
}
86+
87+
$i = 0;
88+
foreach ($authorIds as $authorId) {
89+
$statement->bindValue(sprintf('id_%d', $i), $authorId);
90+
++$i;
91+
}
92+
93+
$result = $statement->execute();
94+
95+
if ($result === false) {
96+
throw new RuntimeException('Failed to execute statement');
97+
}
98+
99+
$authors = [];
100+
101+
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
102+
/**
103+
* @var array{
104+
* id: string,
105+
* name: string,
106+
* email: null|string
107+
* } $row
108+
*/
109+
$authors[] = new Author(
110+
$row['id'],
111+
$row['name'],
112+
$row['email'],
113+
);
114+
}
115+
116+
return $authors;
117+
}
118+
64119
public function save(Author $author): void
65120
{
66121
$sqlite = $this->sqliteFactory->create();

0 commit comments

Comments
 (0)