Completed
Pull Request — 8.x-3.x (#525)
by Philipp
02:22
created

SchemaPluginBase::resolveType()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 10
nc 5
nop 4
dl 0
loc 18
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\graphql\Plugin\GraphQL\Schemas;
4
5
use Drupal\Component\Plugin\PluginBase;
6
use Drupal\Core\Cache\CacheableDependencyInterface;
7
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
8
use Drupal\graphql\Plugin\FieldPluginManager;
9
use Drupal\graphql\Plugin\MutationPluginManager;
10
use Drupal\graphql\Plugin\SchemaBuilderInterface;
11
use Drupal\graphql\Plugin\SchemaPluginInterface;
12
use Drupal\graphql\Plugin\TypePluginManagerAggregator;
13
use GraphQL\Type\Definition\ObjectType;
14
use GraphQL\Type\Schema;
15
use GraphQL\Type\SchemaConfig;
16
use Symfony\Component\DependencyInjection\ContainerInterface;
17
18
abstract class SchemaPluginBase extends PluginBase implements SchemaPluginInterface, SchemaBuilderInterface, ContainerFactoryPluginInterface, CacheableDependencyInterface {
19
20
21
  /**
22
   * @var \Drupal\graphql\Plugin\FieldPluginManager
23
   */
24
  protected $fieldManager;
25
26
  /**
27
   * @var \Drupal\graphql\Plugin\MutationPluginManager
28
   */
29
  protected $mutationManager;
30
31
  /**
32
   * @var \Drupal\graphql\Plugin\TypePluginManagerAggregator
33
   */
34
  protected $typeManagers;
35
36
  /**
37
   * @var array
38
   */
39
  protected $fields = [];
40
41
  /**
42
   * @var array
43
   */
44
  protected $mutations = [];
45
46
  /**
47
   * @var array
48
   */
49
  protected $types = [];
50
51
  /**
52
   * {@inheritdoc}
53
   */
54
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
55
    return new static(
56
      $configuration,
57
      $plugin_id,
58
      $plugin_definition,
59
      $container->get('plugin.manager.graphql.field'),
60
      $container->get('plugin.manager.graphql.mutation'),
61
      $container->get('graphql.type_manager_aggregator')
62
    );
63
  }
64
65
  /**
66
   * SchemaPluginBase constructor.
67
   *
68
   * @param array $configuration
69
   *   The plugin configuration array.
70
   * @param string $pluginId
71
   *   The plugin id.
72
   * @param array $pluginDefinition
73
   *   The plugin definition array.
74
   * @param \Drupal\graphql\Plugin\FieldPluginManager $fieldManager
75
   * @param \Drupal\graphql\Plugin\MutationPluginManager $mutationManager
76
   * @param \Drupal\graphql\Plugin\TypePluginManagerAggregator $typeManagers
77
   */
78 View Code Duplication
  public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
79
    $configuration,
80
    $pluginId,
81
    $pluginDefinition,
82
    FieldPluginManager $fieldManager,
83
    MutationPluginManager $mutationManager,
84
    TypePluginManagerAggregator $typeManagers
85
  ) {
86
    parent::__construct($configuration, $pluginId, $pluginDefinition);
87
    $this->fieldManager = $fieldManager;
88
    $this->mutationManager = $mutationManager;
89
    $this->typeManagers = $typeManagers;
90
  }
91
92
  /**
93
   * {@inheritdoc}
94
   */
95
  public function getSchema() {
96
    $config = new SchemaConfig();
97
98
    if ($this->hasMutations()) {
99
      $config->setMutation(new ObjectType([
100
        'name' => 'MutationRoot',
101
        'fields' => function () {
102
          return $this->getMutations();
103
        },
104
      ]));
105
    }
106
107
    $config->setQuery(new ObjectType([
108
      'name' => 'QueryRoot',
109
      'fields' => function () {
110
        return $this->getFields('Root');
111
      },
112
    ]));
113
114
    $config->setTypes(function () {
115
      return $this->getTypes();
116
    });
117
118
    $config->setTypeLoader(function ($name) {
119
      return $this->getType($name);
120
    });
121
122
    return new Schema($config);
123
  }
124
125
  /**
126
   * @return bool
127
   */
128
  public function hasFields($type) {
129
    return isset($this->pluginDefinition['field_association_map'][$type]);
130
  }
131
132
  /**
133
   * @return bool
134
   */
135
  public function hasMutations() {
136
    return !empty($this->pluginDefinition['mutation_map']);
137
  }
138
139
  /**
140
   * @return bool
141
   */
142
  public function hasType($name) {
143
    return isset($this->pluginDefinition['type_map'][$name]);
144
  }
145
146
  /**
147
   * @return array
148
   */
149
  public function getFields($type) {
150
    $association = $this->pluginDefinition['field_association_map'];
151
    $fields = $this->pluginDefinition['field_map'];
152
153
    if (isset($association[$type])) {
154
      return $this->processFields(array_map(function ($id) use ($fields) {
155
        return $fields[$id];
156
      }, $association[$type]));
157
    }
158
159
    return [];
160
  }
161
162
  /**
163
   * @return array
164
   */
165
  public function getMutations() {
166
    return $this->processMutations($this->pluginDefinition['mutation_map']);
167
  }
168
169
  /**
170
   * @return array
171
   */
172
  public function getTypes() {
173
    return array_map(function ($name) {
174
      return $this->getType($name);
175
    }, array_keys($this->pluginDefinition['type_map']));
176
  }
177
178
  /**
179
   * Retrieve the list of derivatives associated with a composite type.
180
   *
181
   * @return string[]
182
   *   The list of possible sub typenames.
183
   */
184
  public function getSubTypes($name) {
185
    $association = $this->pluginDefinition['type_association_map'];
186
    return isset($association[$name]) ? $association[$name] : [];
187
  }
188
189
  /**
190
   * Resolve the matching type.
191
   */
192
  public function resolveType($name, $value, $context, $info) {
193
    $association = $this->pluginDefinition['type_association_map'];
194
    $types = $this->pluginDefinition['type_map'];
195
    if (!isset($association[$name])) {
196
      return NULL;
197
    }
198
199
    foreach ($association[$name] as $type) {
200
      // TODO: Avoid loading the type for the check. Make it static!
201
      if (isset($types[$type]) && $instance = $this->buildType($types[$type])) {
202
        if ($instance->isTypeOf($value, $context, $info)) {
203
          return $instance;
204
        }
205
      }
206
    }
207
208
    return NULL;
209
  }
210
211
  /**
212
   * @param $name
213
   *
214
   * @return mixed
215
   */
216
  public function getType($name) {
217
    $types = $this->pluginDefinition['type_map'];
218
    $references = $this->pluginDefinition['type_reference_map'];
219
    if (isset($types[$name])) {
220
      return $this->buildType($this->pluginDefinition['type_map'][$name]);
221
    }
222
223
    do {
224
      if (isset($references[$name])) {
225
        return $this->buildType($types[$references[$name]]);
226
      }
227
    } while (($pos = strpos($name, ':')) !== FALSE && $name = substr($name, 0, $pos));
228
229
    throw new \LogicException(sprintf('Missing type %s.', $name));
230
  }
231
232
  /**
233
   * @param $mutations
234
   *
235
   * @return array
236
   */
237
  public function processMutations($mutations) {
238
    return array_map([$this, 'buildMutation'], $mutations);
239
  }
240
241
  /**
242
   * @param $fields
243
   *
244
   * @return array
245
   */
246
  public function processFields($fields) {
247
    return array_map([$this, 'buildField'], $fields);
248
  }
249
250
  /**
251
   * @param $args
252
   *
253
   * @return array
254
   */
255
  public function processArguments($args) {
256
    return array_map(function ($arg) {
257
      return [
258
        'type' => $this->processType($arg['type']),
259
      ] + $arg;
260
    }, $args);
261
  }
262
263
  /**
264
   * @param $type
265
   *
266
   * @return mixed
267
   */
268
  public function processType($type) {
269
    list($type, $decorators) = $type;
270
271
    return array_reduce($decorators, function ($type, $decorator) {
272
      return $decorator($type);
273
    }, $this->getType($type));
274
  }
275
276
  /**
277
   * @param $type
278
   *
279
   * @return \Drupal\graphql\Plugin\GraphQL\Types\TypePluginBase
280
   */
281
  protected function buildType($type) {
282
    if (!isset($this->types[$type['id']])) {
283
      $creator = [$type['class'], 'createInstance'];
284
      $manager = $this->typeManagers->getTypeManager($type['type']);
285
      $this->types[$type['id']] = $creator($this, $manager, $type['definition'], $type['id']);
286
    }
287
288
    return $this->types[$type['id']];
289
  }
290
291
  /**
292
   * @param $field
293
   *
294
   * @return mixed
295
   */
296 View Code Duplication
  protected function buildField($field) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
297
    if (!isset($this->fields[$field['id']])) {
298
      $creator = [$field['class'], 'createInstance'];
299
      $this->fields[$field['id']] = $creator($this, $this->fieldManager, $field['definition'], $field['id']);
300
    }
301
302
    return $this->fields[$field['id']];
303
  }
304
305
  /**
306
   * @param $mutation
307
   *
308
   * @return mixed
309
   */
310 View Code Duplication
  protected function buildMutation($mutation) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
311
    if (!isset($this->mutations[$mutation['id']])) {
312
      $creator = [$mutation['class'], 'createInstance'];
313
      $this->mutations[$mutation['id']] = $creator($this, $this->mutationManager, $mutation['definition'], $mutation['id']);
314
    }
315
316
    return $this->mutations[$mutation['id']];
317
  }
318
319
  /**
320
   * {@inheritdoc}
321
   */
322
  public function getCacheContexts() {
323
    return [];
324
  }
325
326
  /**
327
   * {@inheritdoc}
328
   */
329
  public function getCacheTags() {
330
    return $this->pluginDefinition['schema_cache_tags'];
331
  }
332
333
  /**
334
   * {@inheritdoc}
335
   */
336
  public function getCacheMaxAge() {
337
    return $this->pluginDefinition['schema_cache_max_age'];
338
  }
339
}
340