DrupalDriver   B
last analyzed

Complexity

Total Complexity 51

Size/Duplication

Total Lines 378
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 51
lcom 1
cbo 2
dl 0
loc 378
rs 7.92
c 0
b 0
f 0

37 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 2
A getRandom() 0 3 1
A bootstrap() 0 4 1
A isBootstrapped() 0 4 1
A userCreate() 0 3 1
A userDelete() 0 3 1
A processBatch() 0 3 1
A userAddRole() 0 3 1
A fetchWatchdog() 0 3 1
A clearCache() 0 3 1
A getSubDriverPaths() 0 8 2
A setCore() 0 6 2
A setCoreFromVersion() 0 4 1
A getCore() 0 3 1
A createNode() 0 3 1
A nodeDelete() 0 3 1
A runCron() 0 5 2
A createTerm() 0 3 1
A termDelete() 0 3 1
A roleCreate() 0 3 1
A roleDelete() 0 3 1
A isField() 0 3 1
A languageCreate() 0 3 1
A languageDelete() 0 3 1
A configGet() 0 3 1
A configSet() 0 3 1
A clearStaticCaches() 0 3 1
A createEntity() 0 3 1
A entityDelete() 0 3 1
A startCollectingMail() 0 3 1
A stopCollectingMail() 0 3 1
A getMail() 0 3 1
A clearMail() 0 3 1
A sendMail() 0 3 1
A login() 0 5 2
A logout() 0 5 2
B getDrupalVersion() 0 43 9

How to fix   Complexity   

Complex Class

Complex classes like DrupalDriver often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DrupalDriver, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Drupal\Driver;
4
5
use Drupal\Driver\Cores\CoreAuthenticationInterface;
6
use Drupal\Driver\Exception\BootstrapException;
7
8
use Behat\Behat\Tester\Exception\PendingException;
9
10
/**
11
 * Fully bootstraps Drupal and uses native API calls.
12
 */
13
class DrupalDriver implements DriverInterface, SubDriverFinderInterface, AuthenticationDriverInterface {
14
15
  /**
16
   * Track whether Drupal has been bootstrapped.
17
   *
18
   * @var bool
19
   */
20
  private $bootstrapped = FALSE;
21
22
  /**
23
   * Drupal core object.
24
   *
25
   * @var \Drupal\Driver\Cores\CoreInterface
26
   */
27
  public $core;
28
29
  /**
30
   * System path to the Drupal installation.
31
   *
32
   * @var string
33
   */
34
  private $drupalRoot;
35
36
  /**
37
   * URI for the Drupal installation.
38
   *
39
   * @var string
40
   */
41
  private $uri;
42
43
  /**
44
   * Drupal core version.
45
   *
46
   * @var int
47
   */
48
  public $version;
49
50
  /**
51
   * Set Drupal root and URI.
52
   *
53
   * @param string $drupal_root
54
   *   The Drupal root path.
55
   * @param string $uri
56
   *   The URI for the Drupal installation.
57
   *
58
   * @throws \Drupal\Driver\Exception\BootstrapException
59
   *   Thrown when the Drupal installation is not found in the given root path.
60
   */
61
  public function __construct($drupal_root, $uri) {
62
    $this->drupalRoot = realpath($drupal_root);
63
    if (!$this->drupalRoot) {
64
      throw new BootstrapException(sprintf('No Drupal installation found at %s', $drupal_root));
65
    }
66
    $this->uri = $uri;
67
    $this->version = $this->getDrupalVersion();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getDrupalVersion() can also be of type double or string. However, the property $version is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
68
  }
69
70
  /**
71
   * {@inheritdoc}
72
   */
73
  public function getRandom() {
74
    return $this->getCore()->getRandom();
75
  }
76
77
  /**
78
   * {@inheritdoc}
79
   */
80
  public function bootstrap() {
81
    $this->getCore()->bootstrap();
82
    $this->bootstrapped = TRUE;
83
  }
84
85
  /**
86
   * {@inheritdoc}
87
   */
88
  public function isBootstrapped() {
89
    // Assume the blackbox is always bootstrapped.
90
    return $this->bootstrapped;
91
  }
92
93
  /**
94
   * {@inheritdoc}
95
   */
96
  public function userCreate(\stdClass $user) {
97
    $this->getCore()->userCreate($user);
98
  }
99
100
  /**
101
   * {@inheritdoc}
102
   */
103
  public function userDelete(\stdClass $user) {
104
    $this->getCore()->userDelete($user);
105
  }
106
107
  /**
108
   * {@inheritdoc}
109
   */
110
  public function processBatch() {
111
    $this->getCore()->processBatch();
112
  }
113
114
  /**
115
   * {@inheritdoc}
116
   */
117
  public function userAddRole(\stdClass $user, $role_name) {
118
    $this->getCore()->userAddRole($user, $role_name);
119
  }
120
121
  /**
122
   * {@inheritdoc}
123
   */
124
  public function fetchWatchdog($count = 10, $type = NULL, $severity = NULL) {
125
    throw new PendingException(sprintf('Currently no ability to access watchdog entries in %s', $this));
126
  }
127
128
  /**
129
   * {@inheritdoc}
130
   */
131
  public function clearCache($type = NULL) {
132
    $this->getCore()->clearCache();
133
  }
134
135
  /**
136
   * {@inheritdoc}
137
   */
138
  public function getSubDriverPaths() {
139
    // Ensure system is bootstrapped.
140
    if (!$this->isBootstrapped()) {
141
      $this->bootstrap();
142
    }
143
144
    return $this->getCore()->getExtensionPathList();
145
  }
146
147
  /**
148
   * Determine major Drupal version.
149
   *
150
   * @return int
151
   *   The major Drupal version.
152
   *
153
   * @throws \Drupal\Driver\Exception\BootstrapException
154
   *   Thrown when the Drupal version could not be determined.
155
   *
156
   * @see drush_drupal_version()
157
   */
158
  public function getDrupalVersion() {
159
    if (!isset($this->version)) {
160
      // Support 6, 7 and 8.
161
      $version_constant_paths = [
162
        // Drupal 6.
163
        '/modules/system/system.module',
164
        // Drupal 7.
165
        '/includes/bootstrap.inc',
166
        // Drupal 8.
167
        '/autoload.php',
168
        '/core/includes/bootstrap.inc',
169
      ];
170
171
      if ($this->drupalRoot === FALSE) {
172
        throw new BootstrapException('`drupal_root` parameter must be defined.');
173
      }
174
175
      foreach ($version_constant_paths as $path) {
176
        if (file_exists($this->drupalRoot . $path)) {
177
          require_once $this->drupalRoot . $path;
178
        }
179
      }
180
      if (defined('VERSION')) {
181
        $version = VERSION;
182
      }
183
      elseif (defined('\Drupal::VERSION')) {
184
        $version = \Drupal::VERSION;
185
      }
186
      else {
187
        throw new BootstrapException('Unable to determine Drupal core version. Supported versions are 6, 7, and 8.');
188
      }
189
190
      // Extract the major version from VERSION.
191
      $version_parts = explode('.', $version);
192
      if (is_numeric($version_parts[0])) {
193
        $this->version = (integer) $version_parts[0] < 8 ? $version_parts[0] : 8;
0 ignored issues
show
Documentation Bug introduced by
It seems like (int) $version_parts[0] ...? $version_parts[0] : 8 can also be of type double or string. However, the property $version is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
194
      }
195
      else {
196
        throw new BootstrapException(sprintf('Unable to extract major Drupal core version from version string %s.', $version));
197
      }
198
    }
199
    return $this->version;
200
  }
201
202
  /**
203
   * Instantiate and set Drupal core class.
204
   *
205
   * @param array $available_cores
206
   *   A major-version-keyed array of available core controllers.
207
   */
208
  public function setCore(array $available_cores) {
209
    if (!isset($available_cores[$this->version])) {
210
      throw new BootstrapException(sprintf('There is no available Drupal core controller for Drupal version %s.', $this->version));
211
    }
212
    $this->core = $available_cores[$this->version];
213
  }
214
215
  /**
216
   * Automatically set the core from the current version.
217
   */
218
  public function setCoreFromVersion() {
219
    $core = '\Drupal\Driver\Cores\Drupal' . $this->getDrupalVersion();
220
    $this->core = new $core($this->drupalRoot, $this->uri);
221
  }
222
223
  /**
224
   * Return current core.
225
   */
226
  public function getCore() {
227
    return $this->core;
228
  }
229
230
  /**
231
   * {@inheritdoc}
232
   */
233
  public function createNode($node) {
234
    return $this->getCore()->nodeCreate($node);
235
  }
236
237
  /**
238
   * {@inheritdoc}
239
   */
240
  public function nodeDelete($node) {
241
    return $this->getCore()->nodeDelete($node);
242
  }
243
244
  /**
245
   * {@inheritdoc}
246
   */
247
  public function runCron() {
248
    if (!$this->getCore()->runCron()) {
249
      throw new \Exception('Failed to run cron.');
250
    }
251
  }
252
253
  /**
254
   * {@inheritdoc}
255
   */
256
  public function createTerm(\stdClass $term) {
257
    return $this->getCore()->termCreate($term);
258
  }
259
260
  /**
261
   * {@inheritdoc}
262
   */
263
  public function termDelete(\stdClass $term) {
264
    return $this->getCore()->termDelete($term);
265
  }
266
267
  /**
268
   * {@inheritdoc}
269
   */
270
  public function roleCreate(array $permissions) {
271
    return $this->getCore()->roleCreate($permissions);
272
  }
273
274
  /**
275
   * {@inheritdoc}
276
   */
277
  public function roleDelete($rid) {
278
    $this->getCore()->roleDelete($rid);
279
  }
280
281
  /**
282
   * {@inheritdoc}
283
   */
284
  public function isField($entity_type, $field_name) {
285
    return $this->getCore()->isField($entity_type, $field_name);
286
  }
287
288
  /**
289
   * {@inheritdoc}
290
   */
291
  public function languageCreate($language) {
292
    return $this->getCore()->languageCreate($language);
293
  }
294
295
  /**
296
   * {@inheritdoc}
297
   */
298
  public function languageDelete($language) {
299
    $this->getCore()->languageDelete($language);
300
  }
301
302
  /**
303
   * {@inheritdoc}
304
   */
305
  public function configGet($name, $key) {
306
    return $this->getCore()->configGet($name, $key);
307
  }
308
309
  /**
310
   * {@inheritdoc}
311
   */
312
  public function configSet($name, $key, $value) {
313
    $this->getCore()->configSet($name, $key, $value);
314
  }
315
316
  /**
317
   * {@inheritdoc}
318
   */
319
  public function clearStaticCaches() {
320
    $this->getCore()->clearStaticCaches();
321
  }
322
323
  /**
324
   * {@inheritdoc}
325
   */
326
  public function createEntity($entity_type, \stdClass $entity) {
327
    return $this->getCore()->entityCreate($entity_type, $entity);
328
  }
329
330
  /**
331
   * {@inheritdoc}
332
   */
333
  public function entityDelete($entity_type, \stdClass $entity) {
334
    return $this->getCore()->entityDelete($entity_type, $entity);
335
  }
336
337
  /**
338
   * {@inheritdoc}
339
   */
340
  public function startCollectingMail() {
341
    return $this->getCore()->startCollectingMail();
342
  }
343
344
  /**
345
   * {@inheritdoc}
346
   */
347
  public function stopCollectingMail() {
348
    return $this->getCore()->stopCollectingMail();
349
  }
350
351
  /**
352
   * {@inheritdoc}
353
   */
354
  public function getMail() {
355
    return $this->getCore()->getMail();
356
  }
357
358
  /**
359
   * {@inheritdoc}
360
   */
361
  public function clearMail() {
362
    return $this->getCore()->clearMail();
363
  }
364
365
  /**
366
   * {@inheritdoc}
367
   */
368
  public function sendMail($body, $subject, $to, $langcode) {
369
    return $this->getCore()->sendMail($body, $subject, $to, $langcode);
370
  }
371
372
  /**
373
   * {@inheritdoc}
374
   */
375
  public function login(\stdClass $user) {
376
    if ($this->getCore() instanceof CoreAuthenticationInterface) {
377
      $this->getCore()->login($user);
378
    }
379
  }
380
381
  /**
382
   * {@inheritdoc}
383
   */
384
  public function logout() {
385
    if ($this->getCore() instanceof CoreAuthenticationInterface) {
386
      $this->getCore()->logout();
387
    }
388
  }
389
390
}
391