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

PluggableSchemaBuilder::find()   C

Complexity

Conditions 12
Paths 4

Size

Total Lines 41
Code Lines 22

Duplication

Lines 7
Ratio 17.07 %

Importance

Changes 0
Metric Value
cc 12
eloc 22
nc 4
nop 3
dl 7
loc 41
rs 5.1612
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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, $invert = FALSE) {
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
        if (empty($name)) {
75
          throw new InvalidPluginDefinitionException($id, 'Invalid plugin definition. No name defined.');
76
        }
77
78
        if (!array_key_exists($name, $items) || $items[$name]['weight'] < $definition['weight']) {
79
          if ((($invert && !$selector($definition)) || $selector($definition))) {
80
            $items[$name] = [
81
              'weight' => $definition['weight'],
82
              'id' => $id,
83
              'type' => $type,
84
            ];
85
          }
86
        }
87
      }
88
    }
89
90
    // Sort the plugins so that the ones with higher weight come first.
91 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...
92
      if ($a['weight'] === $b['weight']) {
93
        return 0;
94
      }
95
96
      return ($a['weight'] < $b['weight']) ? 1 : -1;
97
    });
98
99
    // @TODO: Add support configurable plugins.
100
    return array_map(function (array $item) {
101
      return $this->getInstance($item['type'], $item['id']);
102
    }, $items);
103
  }
104
105
  /**
106
   * {@inheritdoc}
107
   */
108
  public function findByName($name, array $types) {
109
    $possibilities = array_reverse(explode(':', $name));
110
111
    foreach ($possibilities as $possibility) {
112
      $result = $this->find(function($definition) use ($possibility) {
113
        return $definition['name'] === $possibility;
114
      }, $types);
115
116
      if (!empty($result)) {
117
        return array_pop($result);
118
      }
119
    }
120
121
    throw new InvalidPluginDefinitionException(null, sprintf('Plugin for type %s could not be found.', $name));
122
  }
123
124
  /**
125
   * Creates a plugin instance cache identifier.
126
   *
127
   * @param string $pluginType
128
   *   The plugin type.
129
   * @param string $pluginId
130
   *   The plugin id.
131
   * @param array $pluginConfiguration
132
   *   The plugin configuration.
133
   *
134
   * @return string
135
   */
136
  protected function getCacheIdentifier($pluginType, $pluginId, array $pluginConfiguration) {
137
    if (empty($pluginConfiguration)) {
138
      return "$pluginType:::$pluginId";
139
    }
140
141
    $configCid = md5(serialize($this->sortRecursive($pluginConfiguration)));
142
    return "$pluginType:::$pluginId:::$configCid";
143
  }
144
145
  /**
146
   * Recursively sorts an array.
147
   *
148
   * Useful for generating a cache identifiers.
149
   *
150
   * @param array $subject
151
   *   The array to sort.
152
   *
153
   * @return array
154
   *   The sorted array.
155
   */
156
  protected function sortRecursive(array $subject) {
157
    asort($subject);
158
    foreach ($subject as $key => $item) {
159
      if (is_array($item)) {
160
        $subject[$key] = $this->sortRecursive($item);
161
      }
162
    }
163
164
    return $subject;
165
  }
166
167
  /**
168
   * {@inheritdoc}
169
   */
170
  public function __sleep() {
171
    // Don't write the plugin instances into the cache.
172
    return array_diff($this->sleepDependencies(), ['instances']);
173
  }
174
175
}
176