-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathProcessGraphQL.module
276 lines (245 loc) · 8.51 KB
/
ProcessGraphQL.module
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
<?php namespace ProcessWire;
use GraphQL\GraphQL;
use GraphQL\Error\DebugFlag;
use ProcessWire\GraphQL\Permissions;
use ProcessWire\HookEvent;
use ProcessWire\GraphQL\Schema;
use Processwire\ProcessGraphQLConfig;
class ProcessGraphQL extends Process implements Module {
const pageName = 'graphql';
public static function getModuleInfo()
{
return array(
'title' => 'GraphQL',
'version' => '2.0.0',
'summary' => 'GraphQL for ProcessWire.',
'href' => 'https://github.com/dadish/ProcessGraphql',
'singular' => true,
'autoload' => 'process=ProcessTemplate',
'icon' => 'object-group',
'requires' => array("PHP>=7.4", "ProcessWire>=3.0.210"),
);
}
/**
* Bootstrap the module
*/
public function init()
{
require_once $this->config->paths->site . 'modules/ProcessGraphQL/vendor/autoload.php';
$this->addHookAfter('Template::changed', $this, 'hookTemplateNameChange');
}
/**
* The hook for modifying the GraphQL schema types by the user.
* The schema is an array of types that will be set to GraphQL types.
* Custom types could be added bu just appending them into an array.
* See the documentation of the library used by this module to learn more
* @see The GraphQL lib https://github.com/webonyx/graphql-php
* @param $schema
* @return $schema
*/
public function ___modifySchema($schema) {
return $schema;
}
/**
* Updates the legalTemplates on name change. Template names for ProcessWire
* are not necessarily valid for GraphQL field naming. Those names that are
* not compatible are removed from legalFields, those that are compatible
* are updated when changed.
* @param HookEvent $event ProcessWire hook $event object.
*/
public function hookTemplateNameChange(HookEvent $event)
{
$whatChanged = $event->arguments[0];
$oldName = $event->arguments[1];
$newName = $event->arguments[2];
// do nothing if name has not changed
if ($whatChanged !== 'name') return;
// do nothing if template is not in legalTemplates
if (!in_array($oldName, $this->legalTemplates)) return;
// remove the oldName from the legalTemplates
$index = array_search($oldName, $this->legalTemplates);
$legalTemplates = array_slice($this->legalTemplates, 0);
array_splice($legalTemplates, $index, 1);
$this->message("Removed `$oldName` from the legalTemplates.");
// if newName is compatible with the module then add it into legalTemplates
if (ProcessGraphQLConfig::isLegalTemplateName($newName)) {
$legalTemplates[] = $newName;
$this->message("Added `$newName` into legalTemplaes.");
}
// make sure to remember changes!
$this->modules->saveConfig($this, 'legalTemplates', $legalTemplates);
}
/**
* Returns the GraphiQL GUI for ProcessWire admin when request's header is not
* set to AJAX. Executes GraphQL api if it is AJAX.
* @return string The rendered string of either GraphiQL GUI or GraphQL json
* response
*/
public function ___execute()
{
if ($this->config->ajax) {
$this->pages->setOutputFormatting(true);
return json_encode($this->executeGraphQL(), true);
}
return $this->executeGraphiQLPartial();
}
/**
* Returns a GraphiQL page.
* @return string An HTML string.
*/
public function executeGraphiQL()
{
$this->setupGraphiQLAssets();
$fullFilename = $this->config->paths->site . 'modules/ProcessGraphQL/graphiql/full.php';
return wireRenderFile($fullFilename, [
'fullGraphiQL' => true,
]);
}
/**
* Returns only the necessary parts for the GraphiQL GUI.
* @return string An HTML strin.
*/
public function executeGraphiQLPartial()
{
$this->setupGraphiQLAssets();
$partialFilename = $this->config->paths->site . 'modules/ProcessGraphQL/graphiql/partial.php';
return wireRenderFile($partialFilename, [
'fullGraphiQL' => false,
]);
}
/**
* Setups the GraphiQL js/css assets for ProcessWire to handle in the admin.
*/
public function setupGraphiQLAssets()
{
$this->config->scripts->add("https://unpkg.com/[email protected]/umd/react.production.min.js");
$this->config->scripts->add("https://unpkg.com/[email protected]/umd/react-dom.production.min.js");
$this->config->scripts->add('https://unpkg.com/[email protected]/graphiql.min.js');
$this->config->styles->add('https://unpkg.com/[email protected]/graphiql.css');
$this->config->js($this->className, [
'GraphQLServerUrl' => $this->getGraphQLServerUrl(),
]);
}
/**
* Returns the server url from where the GraphiQL GUI will fetch the api.
* @return string Url of the GraphQL server.
*/
public function getGraphQLServerUrl()
{
$url = $this->GraphQLServerUrl;
if (!$url) $url = $this->pages->get('template=admin, name=' . self::pageName)->url;
return $url;
}
/**
* Retrieves the GraphQL request. Either from php://input or from $_POST.
* @return array An array with two properties inside. `payload` which is a
* GraphQL payload, that includes all operations, including query, mutation...
* And `variables` which is a variables object.
* NOTE: Both `payload` and `variables` are raw strings, that are ready to be consumed
* by `executeGraphQL` method
*/
public function getRequest()
{
if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) {
$rawBody = file_get_contents('php://input');
$requestData = json_decode($rawBody ?: '', true);
} else {
$requestData = $_POST;
}
$payload = isset($requestData['query']) ? $requestData['query'] : "";
if (empty($payload)) {
$payload = isset($requestData['payload']) ? $requestData['payload'] : "";
}
$variables = isset($requestData['variables']) ? $requestData['variables'] : null;
// in case the post is a form data, parse the variables string.
if (is_string($variables)) {
$variables = json_decode($variables, true);
}
return [
'payload' => $payload,
'variables' => $variables
];
}
/**
* Executes GraphQL api.
* @return string GraphQL api JSON response.
*/
public function ___executeGraphQL($payload = "", $variables = null)
{
if (!$payload) {
$request = $this->getRequest();
$payload = $request['payload'];
$variables = $request['variables'];
}
// instantiating Processor and setting the schema
$schema = Schema::getSchema();
Permissions::turnOnApiAccess();
$result = GraphQL::executeQuery($schema, $payload, $this->pages, null, $variables);
$debug = false;
if ($this->config->debug) {
$debug = $debug = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::INCLUDE_TRACE;
}
$response = $result->toArray($debug);
return $response;
}
/**
* The hook for modifying the GraphQL query operation fields by the user.
* The queryFields is an array of fields that will be set to Query operation.
* Custom fields could be added bu just appending them into an array.
* See the documentation of the library used by this module to learn more
* @see The GraphQL lib https://github.com/webonyx/graphql-php
* @param $queryFields
* @return $queryFields
*/
public function ___getQueryFields($queryFields)
{
return $queryFields;
}
/**
* The hook for modifying the GraphQL mutation operation fields by the user.
* The mutationFields is an array of fields that will be set to Mutation operation.
* Custom fields could be added bu just appending them into an array.
* See the documentation of the library used by this module to learn more
* @see The GraphQL lib https://github.com/webonyx/graphql-php
* @param $mutationFields
* @return $mutationFields
*/
public function ___getMutationFields($mutationFields)
{
return $mutationFields;
}
/**
* Install the module page under setup
*/
public function ___install()
{
// create the page
$page = new Page();
$page->template = 'admin';
$page->name = self::pageName;
// set parent to the home->admin->setup
$parent = $this->pages->get($this->config->adminRootPageID)->child("name=setup, include=all");
$page->parent = $parent;
$page->process = $this->className;
// set the page title as module title
$info = self::getModuleInfo();
$page->title = $info['title'];
// save the page and tell the user about it
$page->save();
$this->message("Created page at: {$page->path}");
}
/**
* Delete the module page
*/
public function ___uninstall()
{
// find page by process field
$moduleID = $this->modules->getModuleID($this);
$page = $this->pages->get("process=$moduleID, name=" . self::pageName);
// if the page exists then delete it and tell the user about it
if ($page->id) {
$this->message("Deleting page: {$page->path}");
$page->delete();
}
}
}