1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Drupal\graphql\Plugin\GraphQL; |
4
|
|
|
|
5
|
|
|
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; |
6
|
|
|
use Drupal\Component\Plugin\PluginManagerInterface; |
7
|
|
|
|
8
|
|
|
class SchemaBuilder { |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Static cache of type system plugin instances. |
12
|
|
|
* |
13
|
|
|
* @var \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginInterface |
14
|
|
|
*/ |
15
|
|
|
protected $instances = []; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Static cache of plugin definitions. |
19
|
|
|
* |
20
|
|
|
* @var array |
21
|
|
|
*/ |
22
|
|
|
protected $definitions; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* List of registered type system plugin managers. |
26
|
|
|
* |
27
|
|
|
* @var \Drupal\Component\Plugin\PluginManagerInterface[] |
28
|
|
|
*/ |
29
|
|
|
protected $pluginManagers; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* SchemaBuilder constructor. |
33
|
|
|
* |
34
|
|
|
* @param \Drupal\Component\Plugin\PluginManagerInterface[] $pluginManagers |
35
|
|
|
* List of type system plugin managers. |
36
|
|
|
*/ |
37
|
|
|
public function __construct(array $pluginManagers) { |
38
|
|
|
$this->pluginManagers = $pluginManagers; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Returns the list of sorted plugin definitions. |
43
|
|
|
* |
44
|
|
|
* @return array |
45
|
|
|
* The list of sorted plugin definitions. |
46
|
|
|
*/ |
47
|
|
|
protected function getDefinitions() { |
48
|
|
|
if ($this->definitions == NULL) { |
49
|
|
|
foreach ($this->pluginManagers as $manager) { |
50
|
|
|
foreach ($manager->getDefinitions() as $pluginId => $definition) { |
51
|
|
|
$this->definitions[] = [ |
52
|
|
|
'id' => $pluginId, |
53
|
|
|
'type' => $definition['pluginType'], |
54
|
|
|
'weight' => $definition['weight'], |
55
|
|
|
'manager' => $manager, |
56
|
|
|
'definition' => $definition, |
57
|
|
|
]; |
58
|
|
|
} |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
uasort($this->definitions, '\Drupal\Component\Utility\SortArray::sortByWeightElement'); |
62
|
|
|
$this->definitions = array_reverse($this->definitions); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
return $this->definitions; |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* {@inheritdoc} |
70
|
|
|
*/ |
71
|
|
|
public function find(callable $selector, array $types, $invert = FALSE) { |
72
|
|
|
$instances = []; |
73
|
|
|
foreach ($this->getDefinitions() as $index => $definition) { |
74
|
|
|
$name = $definition['definition']['name']; |
75
|
|
|
if (empty($name)) { |
76
|
|
|
throw new InvalidPluginDefinitionException('Invalid GraphQL plugin definition. No name defined.'); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
if (!array_key_exists($name, $instances) && in_array($definition['definition']['pluginType'], $types)) { |
80
|
|
|
if ((($invert && !$selector($definition['definition'])) || $selector($definition['definition']))) { |
81
|
|
|
$instances[$name] = $this->getInstance($definition['manager'], $definition['type'], $definition['id']); |
82
|
|
|
} |
83
|
|
|
} |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
return $instances; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* {@inheritdoc} |
91
|
|
|
*/ |
92
|
|
|
public function findByName($name, array $types) { |
93
|
|
|
$result = $this->find(function($definition) use ($name) { |
94
|
|
|
return $definition['name'] === $name; |
95
|
|
|
}, $types); |
96
|
|
|
|
97
|
|
|
if (empty($result)) { |
98
|
|
|
throw new InvalidPluginDefinitionException(sprintf('GraphQL plugin with name %s could not be found.', $name)); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
return array_pop($result); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* {@inheritdoc} |
106
|
|
|
*/ |
107
|
|
|
public function findByDataType($dataType, array $types = [ |
108
|
|
|
GRAPHQL_UNION_TYPE_PLUGIN, |
109
|
|
|
GRAPHQL_TYPE_PLUGIN, |
110
|
|
|
GRAPHQL_INTERFACE_PLUGIN, |
111
|
|
|
GRAPHQL_SCALAR_PLUGIN, |
112
|
|
|
]) { |
113
|
|
|
$chain = explode(':', $dataType); |
114
|
|
|
|
115
|
|
|
while ($chain) { |
|
|
|
|
116
|
|
|
$dataType = implode(':', $chain); |
117
|
|
|
|
118
|
|
|
$types = $this->find(function($definition) use ($dataType) { |
119
|
|
|
return isset($definition['data_type']) && $definition['data_type'] == $dataType; |
120
|
|
|
}, $types); |
121
|
|
|
|
122
|
|
|
if (!empty($types)) { |
123
|
|
|
return array_pop($types); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
array_pop($chain); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
return NULL; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* {@inheritdoc} |
134
|
|
|
*/ |
135
|
|
|
public function getMutations() { |
136
|
|
|
return $this->find(function() { |
137
|
|
|
return TRUE; |
138
|
|
|
}, [GRAPHQL_MUTATION_PLUGIN]); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* {@inheritdoc} |
143
|
|
|
*/ |
144
|
|
|
public function getRootFields() { |
145
|
|
|
// Retrieve the list of fields that are explicitly attached to a type. |
146
|
|
|
$attachedFields = array_reduce(array_filter(array_map(function($definition) { |
147
|
|
|
return array_key_exists('fields', $definition['definition']) ? $definition['definition']['fields'] : NULL; |
148
|
|
|
}, $this->getDefinitions())), 'array_merge', []); |
149
|
|
|
|
150
|
|
|
// Retrieve the list of fields that are not attached in any way or |
151
|
|
|
// explicitly attached to the artificial "Root" type. |
152
|
|
|
return $this->find(function($definition) use ($attachedFields) { |
153
|
|
|
return (!in_array($definition['name'], $attachedFields) && empty($definition['parents'])) || in_array('Root', $definition['parents']); |
154
|
|
|
}, [GRAPHQL_FIELD_PLUGIN]); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
protected function getInstance(PluginManagerInterface $manager, $pluginType, $pluginId) { |
158
|
|
|
if (!isset($this->instances[$pluginType][$pluginId])) { |
159
|
|
|
// Initialize the static cache array if necessary. |
160
|
|
|
$this->instances[$pluginType] = isset($this->instances[$pluginType]) ? $this->instances[$pluginType] : []; |
161
|
|
|
|
162
|
|
|
// We do not allow plugin configuration for now. |
163
|
|
|
$instance = $manager->createInstance($pluginId); |
164
|
|
|
if (empty($instance)) { |
165
|
|
|
throw new \LogicException(sprintf('Could not instantiate plugin %s of type %s.', $pluginId, $pluginType)); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
if (!$instance instanceof TypeSystemPluginInterface) { |
169
|
|
|
throw new \LogicException(sprintf('Plugin %s of type %s does not implement \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginInterface.', $pluginId, $pluginType)); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
// Prevent circular dependencies by building the type after constructing the plugin instance. |
173
|
|
|
$this->instances[$pluginType][$pluginId] = $instance; |
174
|
|
|
$this->instances[$pluginType][$pluginId]->buildConfig($this); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
return $this->instances[$pluginType][$pluginId]; |
178
|
|
|
} |
179
|
|
|
} |
180
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.