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

PluggableSchemaBuilder   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 192
Duplicated Lines 3.65 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 7
loc 192
rs 10
c 0
b 0
f 0
wmc 28
lcom 1
cbo 1

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getInstance() 0 19 4
A getCacheIdentifier() 0 8 2
A sortRecursive() 0 10 3
A __sleep() 0 4 1
D find() 7 37 9
A findByDataType() 0 20 4
A findByName() 0 7 1
A findByDataTypeOrName() 0 11 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
          if ($selector($definition)) {
77
            $items[$name] = [
78
              'weight' => $definition['weight'],
79
              'id' => $id,
80
              'type' => $type,
81
            ];
82
          }
83
        }
84
      }
85
    }
86
87
    // Sort the plugins so that the ones with higher weight come first.
88 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...
89
      if ($a['weight'] === $b['weight']) {
90
        return 0;
91
      }
92
93
      return ($a['weight'] < $b['weight']) ? 1 : -1;
94
    });
95
96
    return array_map(function (array $item) {
97
      return $this->getInstance($item['type'], $item['id']);
98
    }, $items);
99
  }
100
101
  /**
102
   * {@inheritdoc}
103
   */
104
  public function findByDataType($type, array $types) {
105
    $parts = explode(':', $type);
106
    $chain = array_reverse(array_reduce($parts, function ($carry, $current) {
107
      return $carry + [implode(':', array_filter([end($carry), $current]))];
108
    }, []), TRUE);
109
110
    $result = $this->find(function($definition) use ($chain) {
111
      if (!empty($definition['type'])) {
112
        foreach ($chain as $priority => $part) {
113
          if ($definition['type'] === $part) {
114
            return TRUE;
115
          }
116
        }
117
      }
118
119
      return FALSE;
120
    }, $types);
121
122
    return array_pop($result);
123
  }
124
125
  public function findByName($name, array $types) {
126
    $result = $this->find(function($definition) use ($name) {
127
      return $definition['name'] === $name;
128
    }, $types);
129
130
    return array_pop($result);
131
  }
132
133
  /**
134
   * {@inheritdoc}
135
   */
136
  public function findByDataTypeOrName($input, array $types) {
137
    if ($type = $this->findByDataType($input, $types)) {
138
      return $type;
139
    }
140
141
    if ($type = $this->findByName($input, $types)) {
142
      return $type;
143
    }
144
145
    return $this->getInstance('scalar', 'undefined');
146
  }
147
148
  /**
149
   * Creates a plugin instance cache identifier.
150
   *
151
   * @param string $pluginType
152
   *   The plugin type.
153
   * @param string $pluginId
154
   *   The plugin id.
155
   * @param array $pluginConfiguration
156
   *   The plugin configuration.
157
   *
158
   * @return string
159
   */
160
  protected function getCacheIdentifier($pluginType, $pluginId, array $pluginConfiguration) {
161
    if (empty($pluginConfiguration)) {
162
      return "$pluginType:::$pluginId";
163
    }
164
165
    $configCid = md5(serialize($this->sortRecursive($pluginConfiguration)));
166
    return "$pluginType:::$pluginId:::$configCid";
167
  }
168
169
  /**
170
   * Recursively sorts an array.
171
   *
172
   * Useful for generating a cache identifiers.
173
   *
174
   * @param array $subject
175
   *   The array to sort.
176
   *
177
   * @return array
178
   *   The sorted array.
179
   */
180
  protected function sortRecursive(array $subject) {
181
    asort($subject);
182
    foreach ($subject as $key => $item) {
183
      if (is_array($item)) {
184
        $subject[$key] = $this->sortRecursive($item);
185
      }
186
    }
187
188
    return $subject;
189
  }
190
191
  /**
192
   * {@inheritdoc}
193
   */
194
  public function __sleep() {
195
    // Don't write the plugin instances into the cache.
196
    return array_diff($this->sleepDependencies(), ['instances']);
197
  }
198
199
}
200