Completed
Pull Request — 8.x-3.x (#401)
by Sebastian
02:17
created

SchemaBuilder::getRootFields()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 1
nop 0
dl 0
loc 12
rs 9.2
c 0
b 0
f 0
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $chain of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
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