-
Notifications
You must be signed in to change notification settings - Fork 61
/
Copy pathSchemaTranscriber.php
132 lines (110 loc) · 3.16 KB
/
SchemaTranscriber.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php
namespace SilverStripe\GraphQL\Schema\Services;
use SilverStripe\Assets\Storage\GeneratedAssetHandler;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Path;
use SilverStripe\GraphQL\QueryHandler\QueryHandler;
use GraphQL\Type\Schema as GraphQLSchema;
use Exception;
use Symfony\Component\Filesystem\Filesystem;
/**
* Persists a graphql schema to a json document consumable by Apollo
*/
class SchemaTranscriber
{
use Injectable;
const CACHE_FILENAME = 'types.graphql';
private GraphQLSchema $schema;
private string $name;
protected GeneratedAssetHandler $assetHandler;
private Filesystem $fs;
private string $rootDir;
/**
* SchemaTranscriber constructor.
*
* @param GraphQLSchema $schema
* @param string $name
* @param string $rootDir Storage path for the generated file.
* Caution: This location may be used by frontend assets relying on GraphQL, e.g. silverstripe/assets.
*/
public function __construct(GraphQLSchema $schema, string $name, string $rootDir = null)
{
$this->fs = new Filesystem();
$this->schema = $schema;
$this->name = $name;
$this->rootDir = $rootDir ?: Path::join(PUBLIC_PATH, '_graphql');
}
/**
* Introspect the schema and persist it to the filesystem
* @throws Exception
*/
public function writeSchemaToFilesystem()
{
try {
$types = $this->introspectTypes();
} catch (Exception $e) {
throw new Exception(sprintf(
'There was an error caching the GraphQL types: %s',
$e->getMessage()
));
}
$this->writeTypes(json_encode($types));
}
public function removeSchemaFromFilesystem(): void
{
$this->fs->remove($this->generateCacheFilename());
}
public function writeTypes(string $content)
{
$this->fs->dumpFile($this->generateCacheFilename(), $content);
}
public function getRootDir(): string
{
return $this->rootDir;
}
public function setRootDir(string $rootDir): SchemaTranscriber
{
$this->rootDir = $rootDir;
return $this;
}
/**
* @throws Exception
*/
private function introspectTypes(): array
{
$handler = QueryHandler::create();
$fragments = $handler->query(
$this->schema,
<<<GRAPHQL
query IntrospectionQuery {
__schema {
types {
kind
name
possibleTypes {
name
}
}
}
}
GRAPHQL
);
if (isset($fragments['errors'])) {
$messages = array_map(function ($error) {
return $error['message'];
}, $fragments['errors'] ?? []);
throw new Exception(sprintf(
'There were some errors with the introspection query: %s',
implode(PHP_EOL, $messages)
));
}
return $fragments;
}
private function generateCacheFilename(): string
{
return Path::join(
$this->rootDir,
$this->name . '.' . SchemaTranscriber::CACHE_FILENAME
);
}
}