Completed
Pull Request — 8.x-3.x (#489)
by Philipp
07:43
created

PluggableSchemaBuilder::getInstance()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 4
nop 3
dl 0
loc 25
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\graphql\Plugin\GraphQL;
4
5
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
6
7
class PluggableSchemaBuilder implements PluggableSchemaBuilderInterface {
8
  use DependencySerializationTrait {
9
    __sleep as sleepDependencies;
10
  }
11
12
  /**
13
   * The type system plugin manager aggregator service.
14
   *
15
   * @var \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginManagerAggregator
16
   */
17
  protected $pluginManagers;
18
19
  /**
20
   * Static cache of type system plugin instances.
21
   *
22
   * @var \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginInterface
23
   */
24
  protected $instances = [];
25
26
  /**
27
   * PluggableSchemaBuilder constructor.
28
   *
29
   * @param \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginManagerAggregator $pluginManagers
30
   *   Type system plugin manager aggregator service.
31
   */
32
  public function __construct(TypeSystemPluginManagerAggregator $pluginManagers) {
33
    $this->pluginManagers = $pluginManagers;
34
  }
35
36
  /**
37
   * {@inheritdoc}
38
   */
39
  public function getInstance($pluginType, $pluginId, array $pluginConfiguration = []) {
40
    $cid = $this->getCacheIdentifier($pluginType, $pluginId, $pluginConfiguration);
41
    if (!isset($this->instances[$cid])) {
42
      $managers = $this->pluginManagers->getPluginManagers($pluginType);
43
      if (empty($managers)) {
44
        throw new \LogicException(sprintf('Could not find %s plugin manager for plugin %s.', $pluginType, $pluginId));
45
      }
46
47
      // We do not allow plugin configuration for now.
48
      $instance = NULL;
49
      foreach ($managers as $manager) {
50
        if($manager->hasDefinition($pluginId)) {
51
          $instance = $manager->createInstance($pluginId, $pluginConfiguration);
52
        }
53
      }
54
55
      if (empty($instance)) {
56
        throw new \LogicException(sprintf('Failed to instantiate plugin %s of type %s.', $pluginId, $pluginType));
57
      }
58
59
      $this->instances[$cid] = $instance;
60
    }
61
62
    return $this->instances[$cid];
63
  }
64
65
  /**
66
   * {@inheritdoc}
67
   */
68
  public function find(callable $selector, array $types) {
69
    $items = [];
70
71
    /** @var \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginManagerInterface $manager */
72
    foreach ($this->pluginManagers as $type => $managers) {
73
      if (!in_array($type, $types)) {
74
        continue;
75
      }
76
77
      foreach ($managers as $manager) {
78
        foreach ($manager->getDefinitions() as $id => $definition) {
79
          $name = $definition['name'];
80
81
          if (!array_key_exists($name, $items) || $items[$name]['weight'] < $definition['weight']) {
82
            if ($selector($definition)) {
83
              $items[$name] = [
84
                'weight' => $definition['weight'],
85
                'id' => $id,
86
                'type' => $type,
87
              ];
88
            }
89
          }
90
        }
91
      }
92
    }
93
94
    // Sort the plugins so that the ones with higher weight come first.
95 View Code Duplication
    usort($items, function (array $a, array $b) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
96
      if ($a['weight'] === $b['weight']) {
97
        return 0;
98
      }
99
100
      return ($a['weight'] < $b['weight']) ? 1 : -1;
101
    });
102
103
    return array_map(function (array $item) {
104
      return $this->getInstance($item['type'], $item['id']);
105
    }, $items);
106
  }
107
108
  /**
109
   * {@inheritdoc}
110
   */
111
  public function findByDataType($type, array $types) {
112
    $parts = explode(':', $type);
113
    $chain = array_reverse(array_reduce($parts, function ($carry, $current) {
114
      return array_merge($carry, [implode(':', array_filter([end($carry), $current]))]);
115
    }, []), TRUE);
116
117
    $result = $this->find(function($definition) use ($chain) {
118
      if (!empty($definition['type'])) {
119
        foreach ($chain as $priority => $part) {
120
          if ($definition['type'] === $part) {
121
            return TRUE;
122
          }
123
        }
124
      }
125
126
      return FALSE;
127
    }, $types);
128
129
    return array_pop($result);
130
  }
131
132
  public function findByName($name, array $types) {
133
    $result = $this->find(function($definition) use ($name) {
134
      return $definition['name'] === $name;
135
    }, $types);
136
137
    return array_pop($result);
138
  }
139
140
  /**
141
   * {@inheritdoc}
142
   */
143
  public function findByDataTypeOrName($input, array $types) {
144
    if ($type = $this->findByDataType($input, $types)) {
145
      return $type;
146
    }
147
148
    if ($type = $this->findByName($input, $types)) {
149
      return $type;
150
    }
151
152
    return $this->getInstance('scalar', 'undefined');
153
  }
154
155
  /**
156
   * Creates a plugin instance cache identifier.
157
   *
158
   * @param string $pluginType
159
   *   The plugin type.
160
   * @param string $pluginId
161
   *   The plugin id.
162
   * @param array $pluginConfiguration
163
   *   The plugin configuration.
164
   *
165
   * @return string
166
   */
167
  protected function getCacheIdentifier($pluginType, $pluginId, array $pluginConfiguration) {
168
    if (empty($pluginConfiguration)) {
169
      return "$pluginType:::$pluginId";
170
    }
171
172
    $configCid = md5(serialize($this->sortRecursive($pluginConfiguration)));
173
    return "$pluginType:::$pluginId:::$configCid";
174
  }
175
176
  /**
177
   * Recursively sorts an array.
178
   *
179
   * Useful for generating a cache identifiers.
180
   *
181
   * @param array $subject
182
   *   The array to sort.
183
   *
184
   * @return array
185
   *   The sorted array.
186
   */
187
  protected function sortRecursive(array $subject) {
188
    asort($subject);
189
    foreach ($subject as $key => $item) {
190
      if (is_array($item)) {
191
        $subject[$key] = $this->sortRecursive($item);
192
      }
193
    }
194
195
    return $subject;
196
  }
197
198
  /**
199
   * {@inheritdoc}
200
   */
201
  public function __sleep() {
202
    // Don't write the plugin instances into the cache.
203
    return array_diff($this->sleepDependencies(), ['instances']);
204
  }
205
206
}
207