Completed
Push — 8.x-3.x ( 6b3e90...213280 )
by Sebastian
02:36
created

SchemaPluginBase::hasFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
rs 10
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\GraphQL\Execution\ResolveContext;
9
use Drupal\graphql\Plugin\FieldPluginManager;
10
use Drupal\graphql\Plugin\MutationPluginManager;
11
use Drupal\graphql\Plugin\SchemaBuilderInterface;
12
use Drupal\graphql\Plugin\SchemaPluginInterface;
13
use Drupal\graphql\Plugin\TypePluginManagerAggregator;
14
use GraphQL\Type\Definition\ObjectType;
15
use GraphQL\Type\Definition\ResolveInfo;
16
use GraphQL\Type\Schema;
17
use GraphQL\Type\SchemaConfig;
18
use Symfony\Component\DependencyInjection\ContainerInterface;
19
20
abstract class SchemaPluginBase extends PluginBase implements SchemaPluginInterface, SchemaBuilderInterface, ContainerFactoryPluginInterface, CacheableDependencyInterface {
21
22
  /**
23
   * The field plugin manager.
24
   *
25
   * @var \Drupal\graphql\Plugin\FieldPluginManager
26
   */
27
  protected $fieldManager;
28
29
  /**
30
   * The mutation plugin manager.
31
   *
32
   * @var \Drupal\graphql\Plugin\MutationPluginManager
33
   */
34
  protected $mutationManager;
35
36
  /**
37
   * The type manager aggregator service.
38
   *
39
   * @var \Drupal\graphql\Plugin\TypePluginManagerAggregator
40
   */
41
  protected $typeManagers;
42
43
  /**
44
   * Static cache of field definitions.
45
   *
46
   * @var array
47
   */
48
  protected $fields = [];
49
50
  /**
51
   * Static cache of mutation definitions.
52
   *
53
   * @var array
54
   */
55
  protected $mutations = [];
56
57
  /**
58
   * Static cache of type instances.
59
   *
60
   * @var array
61
   */
62
  protected $types = [];
63
64
  /**
65
   * {@inheritdoc}
66
   */
67
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
68
    return new static(
69
      $configuration,
70
      $plugin_id,
71
      $plugin_definition,
72
      $container->get('plugin.manager.graphql.field'),
73
      $container->get('plugin.manager.graphql.mutation'),
74
      $container->get('graphql.type_manager_aggregator')
75
    );
76
  }
77
78
  /**
79
   * SchemaPluginBase constructor.
80
   *
81
   * @param array $configuration
82
   *   The plugin configuration array.
83
   * @param string $pluginId
84
   *   The plugin id.
85
   * @param array $pluginDefinition
86
   *   The plugin definition array.
87
   * @param \Drupal\graphql\Plugin\FieldPluginManager $fieldManager
88
   *   The field plugin manager.
89
   * @param \Drupal\graphql\Plugin\MutationPluginManager $mutationManager
90
   *   The mutation plugin manager.
91
   * @param \Drupal\graphql\Plugin\TypePluginManagerAggregator $typeManagers
92
   *   The type manager aggregator service.
93
   */
94 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...
95
    $configuration,
96
    $pluginId,
97
    $pluginDefinition,
98
    FieldPluginManager $fieldManager,
99
    MutationPluginManager $mutationManager,
100
    TypePluginManagerAggregator $typeManagers
101
  ) {
102
    parent::__construct($configuration, $pluginId, $pluginDefinition);
103
    $this->fieldManager = $fieldManager;
104
    $this->mutationManager = $mutationManager;
105
    $this->typeManagers = $typeManagers;
106
  }
107
108
  /**
109
   * {@inheritdoc}
110
   */
111
  public function getSchema() {
112
    $config = new SchemaConfig();
113
114
    if ($this->hasMutations()) {
115
      $config->setMutation(new ObjectType([
116
        'name' => 'MutationRoot',
117
        'fields' => function () {
118
          return $this->getMutations();
119
        },
120
      ]));
121
    }
122
123
    $config->setQuery(new ObjectType([
124
      'name' => 'QueryRoot',
125
      'fields' => function () {
126
        return $this->getFields('Root');
127
      },
128
    ]));
129
130
    $config->setTypes(function () {
131
      return $this->getTypes();
132
    });
133
134
    $config->setTypeLoader(function ($name) {
135
      return $this->getType($name);
136
    });
137
138
    return new Schema($config);
139
  }
140
141
  /**
142
   * {@inheritdoc}
143
   */
144
  public function hasFields($type) {
145
    return isset($this->pluginDefinition['field_association_map'][$type]);
146
  }
147
148
  /**
149
   * {@inheritdoc}
150
   */
151
  public function hasMutations() {
152
    return !empty($this->pluginDefinition['mutation_map']);
153
  }
154
155
  /**
156
   * {@inheritdoc}
157
   */
158
  public function hasType($name) {
159
    return isset($this->pluginDefinition['type_map'][$name]);
160
  }
161
162
  /**
163
   * {@inheritdoc}
164
   */
165
  public function getFields($type) {
166
    $association = $this->pluginDefinition['field_association_map'];
167
    $fields = $this->pluginDefinition['field_map'];
168
169
    if (isset($association[$type])) {
170
      return $this->processFields(array_map(function ($id) use ($fields) {
171
        return $fields[$id];
172
      }, $association[$type]));
173
    }
174
175
    return [];
176
  }
177
178
  /**
179
   * {@inheritdoc}
180
   */
181
  public function getMutations() {
182
    return $this->processMutations($this->pluginDefinition['mutation_map']);
183
  }
184
185
  /**
186
   * {@inheritdoc}
187
   */
188
  public function getTypes() {
189
    return array_map(function ($name) {
190
      return $this->getType($name);
191
    }, array_keys($this->pluginDefinition['type_map']));
192
  }
193
194
  /**
195
   * {@inheritdoc}
196
   */
197
  public function getSubTypes($name) {
198
    $association = $this->pluginDefinition['type_association_map'];
199
    return isset($association[$name]) ? $association[$name] : [];
200
  }
201
202
  /**
203
   * {@inheritdoc}
204
   */
205
  public function resolveType($name, $value, ResolveContext $context, ResolveInfo $info) {
206
    $association = $this->pluginDefinition['type_association_map'];
207
    $types = $this->pluginDefinition['type_map'];
208
    if (!isset($association[$name])) {
209
      return NULL;
210
    }
211
212
    foreach ($association[$name] as $type) {
213
      // TODO: Try to avoid loading the type for the check. Consider to make it static!
214
      if (isset($types[$type]) && $instance = $this->buildType($types[$type])) {
215
        if ($instance->isTypeOf($value, $context, $info)) {
216
          return $instance;
217
        }
218
      }
219
    }
220
221
    return NULL;
222
  }
223
224
  /**
225
   * {@inheritdoc}
226
   */
227
  public function getType($name) {
228
    $types = $this->pluginDefinition['type_map'];
229
    $references = $this->pluginDefinition['type_reference_map'];
230
    if (isset($types[$name])) {
231
      return $this->buildType($this->pluginDefinition['type_map'][$name]);
232
    }
233
234
    do {
235
      if (isset($references[$name])) {
236
        return $this->buildType($types[$references[$name]]);
237
      }
238
    } while (($pos = strpos($name, ':')) !== FALSE && $name = substr($name, 0, $pos));
239
240
    throw new \LogicException(sprintf('Missing type %s.', $name));
241
  }
242
243
  /**
244
   * {@inheritdoc}
245
   */
246
  public function processMutations($mutations) {
247
    return array_map([$this, 'buildMutation'], $mutations);
248
  }
249
250
  /**
251
   * {@inheritdoc}
252
   */
253
  public function processFields($fields) {
254
    return array_map([$this, 'buildField'], $fields);
255
  }
256
257
  /**
258
   * {@inheritdoc}
259
   */
260
  public function processArguments($args) {
261
    return array_map(function ($arg) {
262
      return [
263
        'type' => $this->processType($arg['type']),
264
      ] + $arg;
265
    }, $args);
266
  }
267
268
  /**
269
   * {@inheritdoc}
270
   */
271
  public function processType($type) {
272
    list($type, $decorators) = $type;
273
274
    return array_reduce($decorators, function ($type, $decorator) {
275
      return $decorator($type);
276
    }, $this->getType($type));
277
  }
278
279
  /**
280
   * Retrieves the type instance for the given reference.
281
   *
282
   * @param array $type
283
   *   The type reference.
284
   *
285
   * @return \GraphQL\Type\Definition\Type
286
   *   The type instance.
287
   */
288
  protected function buildType($type) {
289
    if (!isset($this->types[$type['id']])) {
290
      $creator = [$type['class'], 'createInstance'];
291
      $manager = $this->typeManagers->getTypeManager($type['type']);
292
      $this->types[$type['id']] = $creator($this, $manager, $type['definition'], $type['id']);
293
    }
294
295
    return $this->types[$type['id']];
296
  }
297
298
  /**
299
   * Retrieves the field definition for a given field reference.
300
   *
301
   * @param array $field
302
   *   The type reference.
303
   *
304
   * @return array
305
   *   The field definition.
306
   */
307 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...
308
    if (!isset($this->fields[$field['id']])) {
309
      $creator = [$field['class'], 'createInstance'];
310
      $this->fields[$field['id']] = $creator($this, $this->fieldManager, $field['definition'], $field['id']);
311
    }
312
313
    return $this->fields[$field['id']];
314
  }
315
316
  /**
317
   * Retrieves the mutation definition for a given field reference.
318
   *
319
   * @param array $mutation
320
   *   The mutation reference.
321
   *
322
   * @return array
323
   *   The mutation definition.
324
   */
325 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...
326
    if (!isset($this->mutations[$mutation['id']])) {
327
      $creator = [$mutation['class'], 'createInstance'];
328
      $this->mutations[$mutation['id']] = $creator($this, $this->mutationManager, $mutation['definition'], $mutation['id']);
329
    }
330
331
    return $this->mutations[$mutation['id']];
332
  }
333
334
  /**
335
   * {@inheritdoc}
336
   */
337
  public function getCacheContexts() {
338
    return [];
339
  }
340
341
  /**
342
   * {@inheritdoc}
343
   */
344
  public function getCacheTags() {
345
    return $this->pluginDefinition['schema_cache_tags'];
346
  }
347
348
  /**
349
   * {@inheritdoc}
350
   */
351
  public function getCacheMaxAge() {
352
    return $this->pluginDefinition['schema_cache_max_age'];
353
  }
354
}
355