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

PluggableSchemaBuilder   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 168
Duplicated Lines 4.17 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

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

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getInstance() 0 19 4
C find() 7 41 12
A findByName() 0 15 3
A getCacheIdentifier() 0 8 2
A sortRecursive() 0 10 3
A __sleep() 0 4 1

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, $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