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

PluggableSchemaBuilder::getCacheIdentifier()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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