1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Drupal\graphql\Plugin\GraphQL; |
4
|
|
|
|
5
|
|
|
use Drupal\Component\Plugin\Factory\DefaultFactory; |
6
|
|
|
use Drupal\Core\DependencyInjection\DependencySerializationTrait; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* TODO: This thing was just quickly put together to make the PoC work. Fix it! |
10
|
|
|
*/ |
11
|
|
|
class PluggableSchemaBuilder implements PluggableSchemaBuilderInterface { |
12
|
|
|
use DependencySerializationTrait; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* The type system plugin manager aggregator service. |
16
|
|
|
* |
17
|
|
|
* @var \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginManagerAggregator |
18
|
|
|
*/ |
19
|
|
|
protected $pluginManagers; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* PluggableSchemaBuilder constructor. |
23
|
|
|
* |
24
|
|
|
* @param \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginManagerAggregator $pluginManagers |
25
|
|
|
* Type system plugin manager aggregator service. |
26
|
|
|
*/ |
27
|
|
|
public function __construct(TypeSystemPluginManagerAggregator $pluginManagers) { |
28
|
|
|
$this->pluginManagers = $pluginManagers; |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @param $type |
33
|
|
|
* @param $id |
34
|
|
|
* |
35
|
|
|
* @return \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginManagerInterface |
36
|
|
|
*/ |
37
|
|
|
public function getPluginManager($type, $id) { |
38
|
|
|
$managers = $this->pluginManagers->getPluginManagers($type); |
39
|
|
|
foreach ($managers as $manager) { |
40
|
|
|
if ($manager->hasDefinition($id)) { |
41
|
|
|
return $manager; |
42
|
|
|
} |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
throw new \LogicException('Could not find plugin manager.'); |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @param $type |
50
|
|
|
* @param $id |
51
|
|
|
* |
52
|
|
|
* @return mixed |
53
|
|
|
*/ |
54
|
|
|
public function getPluginDefinition($type, $id) { |
55
|
|
|
return $this->getPluginManager($type, $id)->getDefinition($id); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @param $type |
60
|
|
|
* @param $id |
61
|
|
|
* |
62
|
|
|
* @return object |
63
|
|
|
*/ |
64
|
|
|
public function getPluginInstance($type, $id) { |
65
|
|
|
if (!isset($this->plugins[$type][$id])) { |
66
|
|
|
return $this->plugins[$type][$id] = $this->getPluginManager($type, $id)->createInstance($id); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
return $this->plugins[$type][$id]; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @param $type |
74
|
|
|
* @param $id |
75
|
|
|
* |
76
|
|
|
* @return mixed |
77
|
|
|
*/ |
78
|
|
|
public function getDefinition($type, $id) { |
79
|
|
|
return $this->getPluginInstance($type, $id)->getDefinition(); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @param $type |
84
|
|
|
* @param $id |
85
|
|
|
* |
86
|
|
|
* @return mixed |
87
|
|
|
*/ |
88
|
|
|
public function getType($type, $id) { |
89
|
|
|
if (!isset($this->instances[$type][$id])) { |
90
|
|
|
$class = DefaultFactory::getPluginClass($id, $this->getPluginDefinition($type, $id)); |
91
|
|
|
$definition = $this->getDefinition($type, $id); |
92
|
|
|
return $this->instances[$type][$id] = call_user_func([$class, 'createInstance'], $this, $definition, $id); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
return $this->instances[$type][$id]; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* @return array |
100
|
|
|
*/ |
101
|
|
|
public function getTypeMap() { |
102
|
|
|
if (isset($this->typeMap)) { |
103
|
|
|
return $this->typeMap; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
foreach ($this->pluginManagers as $type => $managers) { |
107
|
|
|
if ($type === GRAPHQL_FIELD_PLUGIN || $type === GRAPHQL_MUTATION_PLUGIN) { |
108
|
|
|
continue; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** @var \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginManagerInterface $manager */ |
112
|
|
|
foreach ($managers as $manager) { |
113
|
|
|
foreach ($manager->getDefinitions() as $id => $definition) { |
114
|
|
|
$placeholder = &$this->typeMap[$definition['name']]; |
115
|
|
|
|
116
|
|
|
if (!empty($placeholder)) { |
117
|
|
|
$existing = $this->getPluginDefinition($placeholder[0], $placeholder[1]); |
118
|
|
|
// Do not override if the existing plugin has a higher weight. |
119
|
|
|
if ($existing['weight'] > $definition['weight']) { |
120
|
|
|
continue; |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$placeholder = [$type, $id]; |
125
|
|
|
if (isset($definition['type'])) { |
126
|
|
|
$this->typeMap[$definition['type']] = &$placeholder; |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
return $this->typeMap = array_filter($this->typeMap); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* @return array |
137
|
|
|
*/ |
138
|
|
|
public function getFieldMap() { |
139
|
|
|
if (isset($this->fieldMap)) { |
140
|
|
|
return $this->fieldMap; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
$this->fieldMap = []; |
144
|
|
|
foreach ($this->pluginManagers->getPluginManagers(GRAPHQL_FIELD_PLUGIN) as $manager) { |
145
|
|
|
foreach ($manager->getDefinitions() as $id => $definition) { |
146
|
|
|
$parents = $definition['parents'] ?: ['Root']; |
147
|
|
|
|
148
|
|
View Code Duplication |
foreach ($parents as $parent) { |
|
|
|
|
149
|
|
|
$placeholder = &$this->fieldMap[$parent][$definition['name']]; |
150
|
|
|
|
151
|
|
|
if (!empty($placeholder)) { |
152
|
|
|
// Do not override if the existing plugin has a higher weight. |
153
|
|
|
$existing = $this->getPluginDefinition(GRAPHQL_FIELD_PLUGIN, $placeholder); |
154
|
|
|
if ($existing['weight'] > $definition['weight']) { |
155
|
|
|
continue; |
156
|
|
|
} |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
$placeholder = $id; |
160
|
|
|
} |
161
|
|
|
} |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
return $this->fieldMap; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* @return array |
169
|
|
|
*/ |
170
|
|
|
public function getMutationMap() { |
171
|
|
|
if (isset($this->mutationMap)) { |
172
|
|
|
return $this->mutationMap; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
$this->mutationMap = []; |
176
|
|
|
foreach ($this->pluginManagers->getPluginManagers(GRAPHQL_MUTATION_PLUGIN) as $manager) { |
177
|
|
View Code Duplication |
foreach ($manager->getDefinitions() as $id => $definition) { |
|
|
|
|
178
|
|
|
$placeholder = &$this->mutationMap[$definition['name']]; |
179
|
|
|
|
180
|
|
|
if (!empty($placeholder)) { |
181
|
|
|
// Do not override if the existing plugin has a higher weight. |
182
|
|
|
$existing = $this->getPluginDefinition(GRAPHQL_MUTATION_PLUGIN, $placeholder); |
183
|
|
|
if ($existing['weight'] > $definition['weight']) { |
184
|
|
|
continue; |
185
|
|
|
} |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
$placeholder = $id; |
189
|
|
|
} |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
return $this->mutationMap; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* @param $name |
197
|
|
|
* |
198
|
|
|
* @return mixed |
199
|
|
|
*/ |
200
|
|
|
public function getTypeByName($name) { |
201
|
|
|
$map = $this->getTypeMap(); |
202
|
|
View Code Duplication |
if (isset($map[$name])) { |
|
|
|
|
203
|
|
|
return $this->getType($map[$name][0], $map[$name][1]); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
while (($pos = strpos($name, ':')) !== FALSE && $name = substr($name, 0, $pos)) { |
207
|
|
View Code Duplication |
if (isset($map[$name])) { |
|
|
|
|
208
|
|
|
return $this->getType($map[$name][0], $map[$name][1]); |
209
|
|
|
} |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
throw new \LogicException('Could not find type in type map.'); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* @param $name |
217
|
|
|
* |
218
|
|
|
* @return array |
219
|
|
|
*/ |
220
|
|
|
public function getFieldsByType($name) { |
221
|
|
|
$map = $this->getFieldMap(); |
222
|
|
|
if (empty($map[$name])) { |
223
|
|
|
return []; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
return $this->resolveFields($map[$name]); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* @param $fields |
231
|
|
|
* |
232
|
|
|
* @return array |
233
|
|
|
*/ |
234
|
|
|
public function resolveFields($fields, $pluginType = GRAPHQL_FIELD_PLUGIN) { |
235
|
|
|
return array_map(function ($id) use ($fields, $pluginType) { |
236
|
|
|
$field = $this->getType($pluginType, $id); |
237
|
|
|
list($type, $decorators) = $field['type']; |
238
|
|
|
|
239
|
|
|
$type = array_reduce($decorators, function ($a, $decorator) use ($type) { |
240
|
|
|
return $decorator($a); |
241
|
|
|
}, $this->getTypeByName($type)); |
242
|
|
|
|
243
|
|
|
return [ |
244
|
|
|
'type' => $type, |
245
|
|
|
] + $field; |
246
|
|
|
}, $fields); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* @param $args |
251
|
|
|
* |
252
|
|
|
* @return array |
253
|
|
|
*/ |
254
|
|
|
public function resolveArgs($args) { |
255
|
|
|
return array_map(function ($arg) { |
256
|
|
|
list($type, $decorators) = $arg['type']; |
257
|
|
|
|
258
|
|
|
$type = array_reduce($decorators, function ($a, $decorator) use ($type) { |
259
|
|
|
return $decorator($a); |
260
|
|
|
}, $this->getTypeByName($type)); |
261
|
|
|
|
262
|
|
|
return [ |
263
|
|
|
'type' => $type, |
264
|
|
|
] + $arg; |
265
|
|
|
}, $args); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
} |
269
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.