Drupal7   F
last analyzed

Complexity

Total Complexity 86

Size/Duplication

Total Lines 563
Duplicated Lines 19.36 %

Coupling/Cohesion

Components 3
Dependencies 3

Importance

Changes 0
Metric Value
wmc 86
lcom 3
cbo 3
dl 109
loc 563
rs 2
c 0
b 0
f 0

34 Methods

Rating   Name   Duplication   Size   Complexity  
A clearCache() 0 3 1
A nodeCreate() 3 20 4
A nodeDelete() 0 3 1
A runCron() 0 3 1
A userCreate() 0 18 2
A userDelete() 0 3 1
A processBatch() 0 5 1
A userAddRole() 0 12 2
A checkPermissions() 0 15 5
B roleCreate() 0 27 6
A roleDelete() 0 4 1
B validateDrupalSite() 51 51 7
A expandEntityProperties() 16 16 5
B termCreate() 15 43 9
A termDelete() 0 8 2
A languageCreate() 0 24 4
A languageDelete() 0 34 4
A configGet() 0 3 1
A configGetOriginal() 0 3 1
A configSet() 0 3 1
A getAllPermissions() 7 7 2
A getModuleList() 0 3 1
A getExtensionPathList() 11 11 2
A getEntityFieldTypes() 0 10 3
A isField() 0 4 2
A clearStaticCaches() 0 3 1
B entityCreate() 6 31 7
A entityDelete() 0 6 1
A startCollectingMail() 0 4 1
A stopCollectingMail() 0 4 1
A getMail() 0 4 1
A clearMail() 0 4 1
A sendMail() 0 4 1
A bootstrap() 0 16 3

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Drupal7 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 Drupal7, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Drupal\Driver\Cores;
4
5
use Drupal\Driver\Exception\BootstrapException;
6
7
/**
8
 * Drupal 7 core.
9
 */
10
class Drupal7 extends AbstractCore {
11
12
  /**
13
   * {@inheritdoc}
14
   */
15
  public function bootstrap() {
16
    // Validate, and prepare environment for Drupal bootstrap.
17
    if (!defined('DRUPAL_ROOT')) {
18
      define('DRUPAL_ROOT', $this->drupalRoot);
19
      require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
20
      $this->validateDrupalSite();
21
    }
22
23
    // Bootstrap Drupal.
24
    chdir(DRUPAL_ROOT);
25
    drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
26
    if (empty($GLOBALS['databases'])) {
27
      throw new BootstrapException('Missing database setting, verify the database configuration in settings.php.');
28
    }
29
    drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
30
  }
31
32
  /**
33
   * {@inheritdoc}
34
   */
35
  public function clearCache() {
36
    drupal_flush_all_caches();
37
  }
38
39
  /**
40
   * {@inheritdoc}
41
   */
42
  public function nodeCreate($node) {
43
    // Assign authorship if none exists and `author` is passed.
44 View Code Duplication
    if (!isset($node->uid) && !empty($node->author) && ($user = user_load_by_name($node->author))) {
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...
45
      $node->uid = $user->uid;
46
    }
47
48
    // Convert properties to expected structure.
49
    $this->expandEntityProperties($node);
50
51
    // Attempt to decipher any fields that may be specified.
52
    $this->expandEntityFields('node', $node);
53
54
    // Set defaults that haven't already been set.
55
    $defaults = clone $node;
56
    node_object_prepare($defaults);
57
    $node = (object) array_merge((array) $defaults, (array) $node);
58
59
    node_save($node);
60
    return $node;
61
  }
62
63
  /**
64
   * {@inheritdoc}
65
   */
66
  public function nodeDelete($node) {
67
    node_delete($node->nid);
68
  }
69
70
  /**
71
   * Implements CoreInterface::runCron().
72
   */
73
  public function runCron() {
74
    return drupal_cron_run();
75
  }
76
77
  /**
78
   * {@inheritdoc}
79
   */
80
  public function userCreate(\stdClass $user) {
81
    // Default status to TRUE if not explicitly creating a blocked user.
82
    if (!isset($user->status)) {
83
      $user->status = 1;
84
    }
85
86
    // Clone user object, otherwise user_save() changes the password to the
87
    // hashed password.
88
    $account = clone $user;
89
90
    // Attempt to decipher any fields that may be specified.
91
    $this->expandEntityFields('user', $account);
92
93
    user_save($account, (array) $account);
94
95
    // Store UID.
96
    $user->uid = $account->uid;
97
  }
98
99
  /**
100
   * {@inheritdoc}
101
   */
102
  public function userDelete(\stdClass $user) {
103
    user_cancel([], $user->uid, 'user_cancel_delete');
104
  }
105
106
  /**
107
   * {@inheritdoc}
108
   */
109
  public function processBatch() {
110
    $batch =& batch_get();
111
    $batch['progressive'] = FALSE;
112
    batch_process();
113
  }
114
115
  /**
116
   * {@inheritdoc}
117
   */
118
  public function userAddRole(\stdClass $user, $role_name) {
119
    $role = user_role_load_by_name($role_name);
120
121
    if (!$role) {
122
      throw new \RuntimeException(sprintf('No role "%s" exists.', $role_name));
123
    }
124
125
    user_multiple_role_edit([$user->uid], 'add_role', $role->rid);
126
    $account = user_load($user->uid);
127
    $user->roles = $account->roles;
128
129
  }
130
131
  /**
132
   * Check to make sure that the array of permissions are valid.
133
   *
134
   * @param array $permissions
135
   *   Permissions to check.
136
   * @param bool $reset
137
   *   Reset cached available permissions.
138
   *
139
   * @return bool
140
   *   TRUE or FALSE depending on whether the permissions are valid.
141
   */
142
  protected function checkPermissions(array $permissions, $reset = FALSE) {
143
    $available = &drupal_static(__FUNCTION__);
144
145
    if (!isset($available) || $reset) {
146
      $available = array_keys(module_invoke_all('permission'));
147
    }
148
149
    $valid = TRUE;
150
    foreach ($permissions as $permission) {
151
      if (!in_array($permission, $available)) {
152
        $valid = FALSE;
153
      }
154
    }
155
    return $valid;
156
  }
157
158
  /**
159
   * {@inheritdoc}
160
   */
161
  public function roleCreate(array $permissions) {
162
163
    // Both machine name and permission title are allowed.
164
    $all_permissions = $this->getAllPermissions();
165
166
    foreach ($permissions as $key => $name) {
167
      if (!isset($all_permissions[$name])) {
168
        $search = array_search($name, $all_permissions);
169
        if (!$search) {
170
          throw new \RuntimeException(sprintf("No permission '%s' exists.", $name));
171
        }
172
        $permissions[$key] = $search;
173
      }
174
    }
175
176
    // Create new role.
177
    $role = new \stdClass();
178
    $role->name = $this->random->name(8);
179
    user_role_save($role);
180
    user_role_grant_permissions($role->rid, $permissions);
181
182
    if ($role && !empty($role->rid)) {
183
      return $role->name;
184
    }
185
186
    throw new \RuntimeException(sprintf('Failed to create a role with "" permission(s).', implode(', ', $permissions)));
187
  }
188
189
  /**
190
   * {@inheritdoc}
191
   */
192
  public function roleDelete($role_name) {
193
    $role = user_role_load_by_name($role_name);
194
    user_role_delete((int) $role->rid);
195
  }
196
197
  /**
198
   * {@inheritdoc}
199
   */
200 View Code Duplication
  public function validateDrupalSite() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
201
    if ('default' !== $this->uri) {
202
      // Fake the necessary HTTP headers that Drupal needs:
203
      $drupal_base_url = parse_url($this->uri);
204
      // If there's no url scheme set, add http:// and re-parse the url
205
      // so the host and path values are set accurately.
206
      if (!array_key_exists('scheme', $drupal_base_url)) {
207
        $drupal_base_url = parse_url($this->uri);
208
      }
209
      // Fill in defaults.
210
      $drupal_base_url += [
211
        'path' => NULL,
212
        'host' => NULL,
213
        'port' => NULL,
214
      ];
215
      $_SERVER['HTTP_HOST'] = $drupal_base_url['host'];
216
217
      if ($drupal_base_url['port']) {
218
        $_SERVER['HTTP_HOST'] .= ':' . $drupal_base_url['port'];
219
      }
220
      $_SERVER['SERVER_PORT'] = $drupal_base_url['port'];
221
222
      if (array_key_exists('path', $drupal_base_url)) {
223
        $_SERVER['PHP_SELF'] = $drupal_base_url['path'] . '/index.php';
224
      }
225
      else {
226
        $_SERVER['PHP_SELF'] = '/index.php';
227
      }
228
    }
229
    else {
230
      $_SERVER['HTTP_HOST'] = 'default';
231
      $_SERVER['PHP_SELF'] = '/index.php';
232
    }
233
234
    $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] = $_SERVER['PHP_SELF'];
235
    $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
236
    $_SERVER['REQUEST_METHOD'] = NULL;
237
238
    $_SERVER['SERVER_SOFTWARE'] = NULL;
239
    $_SERVER['HTTP_USER_AGENT'] = NULL;
240
241
    $conf_path = conf_path(TRUE, TRUE);
242
    $conf_file = $this->drupalRoot . "/$conf_path/settings.php";
243
    if (!file_exists($conf_file)) {
244
      throw new BootstrapException(sprintf('Could not find a Drupal settings.php file at "%s"', $conf_file));
245
    }
246
    $drushrc_file = $this->drupalRoot . "/$conf_path/drushrc.php";
247
    if (file_exists($drushrc_file)) {
248
      require_once $drushrc_file;
249
    }
250
  }
251
252
  /**
253
   * Expands properties on the given entity object to the expected structure.
254
   *
255
   * @param object $entity
256
   *   The entity object.
257
   */
258 View Code Duplication
  protected function expandEntityProperties(\stdClass $entity) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
259
    // The created field may come in as a readable date, rather than a
260
    // timestamp.
261
    if (isset($entity->created) && !is_numeric($entity->created)) {
262
      $entity->created = strtotime($entity->created);
263
    }
264
265
    // Map human-readable node types to machine node types.
266
    $types = \node_type_get_types();
267
    foreach ($types as $type) {
268
      if ($entity->type == $type->name) {
269
        $entity->type = $type->type;
270
        continue;
271
      }
272
    }
273
  }
274
275
  /**
276
   * {@inheritdoc}
277
   */
278
  public function termCreate(\stdClass $term) {
279
    // Map vocabulary names to vid, these take precedence over machine names.
280 View Code Duplication
    if (!isset($term->vid)) {
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...
281
      $vocabularies = \taxonomy_get_vocabularies();
282
      foreach ($vocabularies as $vid => $vocabulary) {
283
        if ($vocabulary->name == $term->vocabulary_machine_name) {
284
          $term->vid = $vocabulary->vid;
285
        }
286
      }
287
    }
288
289
    if (!isset($term->vid)) {
290
291
      // Try to load vocabulary by machine name.
292
      $vocabularies = \taxonomy_vocabulary_load_multiple(FALSE, [
293
        'machine_name' => $term->vocabulary_machine_name,
294
      ]);
295
      if (!empty($vocabularies)) {
296
        $vids = array_keys($vocabularies);
297
        $term->vid = reset($vids);
298
      }
299
    }
300
301
    // If `parent` is set, look up a term in this vocab with that name.
302 View Code Duplication
    if (isset($term->parent)) {
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...
303
      $parent = \taxonomy_get_term_by_name($term->parent, $term->vocabulary_machine_name);
304
      if (!empty($parent)) {
305
        $parent = reset($parent);
306
        $term->parent = $parent->tid;
307
      }
308
    }
309
310
    if (empty($term->vid)) {
311
      throw new \Exception(sprintf('No "%s" vocabulary found.', $term->vocabulary_machine_name));
312
    }
313
314
    // Attempt to decipher any fields that may be specified.
315
    $this->expandEntityFields('taxonomy_term', $term);
316
317
    \taxonomy_term_save($term);
318
319
    return $term;
320
  }
321
322
  /**
323
   * {@inheritdoc}
324
   */
325
  public function termDelete(\stdClass $term) {
326
    $status = 0;
327
    if (isset($term->tid)) {
328
      $status = \taxonomy_term_delete($term->tid);
329
    }
330
    // Will be SAVED_DELETED (3) on success.
331
    return $status;
332
  }
333
334
  /**
335
   * {@inheritdoc}
336
   */
337
  public function languageCreate(\stdClass $language) {
338
    if (!module_exists('locale')) {
339
      throw new \Exception(sprintf("%s::%s line %s: This driver requires the 'locale' module be enabled in order to create languages", get_class($this), __FUNCTION__, __LINE__));
340
    }
341
    include_once DRUPAL_ROOT . '/includes/iso.inc';
342
    include_once DRUPAL_ROOT . '/includes/locale.inc';
343
344
    // Get all predefined languages, regardless if they are enabled or not.
345
    $predefined_languages = _locale_get_predefined_list();
346
347
    // If the language code is not valid then throw an InvalidArgumentException.
348
    if (!isset($predefined_languages[$language->langcode])) {
349
      throw new InvalidArgumentException("There is no predefined language with langcode '{$language->langcode}'.");
350
    }
351
352
    // Enable a language only if it has not been enabled already.
353
    $enabled_languages = locale_language_list();
354
    if (!isset($enabled_languages[$language->langcode])) {
355
      locale_add_language($language->langcode);
356
      return $language;
357
    }
358
359
    return FALSE;
360
  }
361
362
  /**
363
   * {@inheritdoc}
364
   */
365
  public function languageDelete(\stdClass $language) {
366
    $langcode = $language->langcode;
367
    // Do not remove English or the default language.
368
    if (!in_array($langcode, [language_default('language'), 'en'])) {
369
      // @see locale_languages_delete_form_submit().
370
      $languages = language_list();
371
      if (isset($languages[$langcode])) {
372
        // Remove translations first.
373
        db_delete('locales_target')
374
          ->condition('language', $langcode)
375
          ->execute();
376
        cache_clear_all('locale:' . $langcode, 'cache');
377
        // With no translations, this removes existing JavaScript translations
378
        // file.
379
        _locale_rebuild_js($langcode);
380
        // Remove the language.
381
        db_delete('languages')
382
          ->condition('language', $langcode)
383
          ->execute();
384
        db_update('node')
385
          ->fields(['language' => ''])
386
          ->condition('language', $langcode)
387
          ->execute();
388
        if ($languages[$langcode]->enabled) {
389
          variable_set('language_count', variable_get('language_count', 1) - 1);
390
        }
391
        module_invoke_all('multilingual_settings_changed');
392
        drupal_static_reset('language_list');
393
      }
394
395
      // Changing the language settings impacts the interface:
396
      cache_clear_all('*', 'cache_page', TRUE);
397
    }
398
  }
399
400
  /**
401
   * {@inheritdoc}
402
   */
403
  public function configGet($name, $key = '') {
404
    throw new \Exception('Getting config is not yet implemented for Drupal 7.');
405
  }
406
407
  /**
408
   * {@inheritdoc}
409
   */
410
  public function configGetOriginal($name, $key = '') {
411
    throw new \Exception('Getting original config is not yet implemented for Drupal 7.');
412
  }
413
414
  /**
415
   * {@inheritdoc}
416
   */
417
  public function configSet($name, $key, $value) {
418
    throw new \Exception('Setting config is not yet implemented for Drupal 7.');
419
  }
420
421
  /**
422
   * Helper function to get all permissions.
423
   *
424
   * @return array
425
   *   Array keyed by permission name, with the human-readable title as the
426
   *   value.
427
   */
428 View Code Duplication
  protected function getAllPermissions() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
429
    $permissions = [];
430
    foreach (module_invoke_all('permission') as $name => $permission) {
431
      $permissions[$name] = $permission['title'];
432
    }
433
    return $permissions;
434
  }
435
436
  /**
437
   * {@inheritdoc}
438
   */
439
  public function getModuleList() {
440
    return module_list();
441
  }
442
443
  /**
444
   * {@inheritdoc}
445
   */
446 View Code Duplication
  public function getExtensionPathList() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
447
    $paths = [];
448
449
    // Get enabled modules.
450
    $modules = $this->getModuleList();
451
    foreach ($modules as $module) {
452
      $paths[] = $this->drupalRoot . DIRECTORY_SEPARATOR . \drupal_get_path('module', $module);
453
    }
454
455
    return $paths;
456
  }
457
458
  /**
459
   * {@inheritdoc}
460
   */
461
  public function getEntityFieldTypes($entity_type, array $base_fields = []) {
462
    $return = [];
463
    $fields = field_info_field_map();
464
    foreach ($fields as $field_name => $field) {
465
      if (array_key_exists($entity_type, $field['bundles'])) {
466
        $return[$field_name] = $field['type'];
467
      }
468
    }
469
    return $return;
470
  }
471
472
  /**
473
   * {@inheritdoc}
474
   */
475
  public function isField($entity_type, $field_name) {
476
    $map = field_info_field_map();
477
    return !empty($map[$field_name]) && array_key_exists($entity_type, $map[$field_name]['bundles']);
478
  }
479
480
  /**
481
   * {@inheritdoc}
482
   */
483
  public function clearStaticCaches() {
484
    drupal_static_reset();
485
  }
486
487
  /**
488
   * {@inheritdoc}
489
   */
490
  public function entityCreate($entity_type, $entity) {
491
    $info = entity_get_info($entity_type);
492
    // If the bundle field is empty, put the inferred bundle value in it.
493
    $bundle_key = $info['entity keys']['bundle'];
494 View Code Duplication
    if (!isset($entity->$bundle_key) && isset($entity->step_bundle)) {
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...
495
      $entity->$bundle_key = $entity->step_bundle;
496
    }
497
498
    // Throw an exception if a bundle is specified but does not exist.
499
    if (isset($entity->$bundle_key) && ($entity->$bundle_key !== NULL)) {
500
      $bundles = $info['bundles'];
501 View Code Duplication
      if (!in_array($entity->$bundle_key, array_keys($bundles))) {
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...
502
        throw new \Exception("Cannot create entity because provided bundle {$entity->$bundle_key} does not exist.");
503
      }
504
    }
505
    if (empty($entity_type)) {
506
      throw new \Exception("You must specify an entity type to create an entity.");
507
    }
508
509
    $this->expandEntityFields($entity_type, $entity);
510
    $createdEntity = entity_create($entity_type, (array) $entity);
511
512
    // In D7 it's possible that $createdEntity is not of class Entity, so we
513
    // must use entity_save().
514
    entity_save($entity_type, $createdEntity);
515
516
    list($id) = entity_extract_ids($entity_type, $createdEntity);
517
    $createdEntity->id = $id;
518
519
    return $createdEntity;
520
  }
521
522
  /**
523
   * {@inheritdoc}
524
   */
525
  public function entityDelete($entity_type, $entity) {
526
    // In D7 it's possible that $entity is not of class Entity, so we must use
527
    // entity_delete().
528
    list($id) = entity_extract_ids($entity_type, $entity);
529
    entity_delete($entity_type, $id);
530
  }
531
532
  /**
533
   * {@inheritdoc}
534
   */
535
  public function startCollectingMail() {
536
    // @todo create a D7 version of this function
537
    throw new \Exception('Mail testing is not yet implemented for Drupal 7.');
538
  }
539
540
  /**
541
   * {@inheritdoc}
542
   */
543
  public function stopCollectingMail() {
544
    // @todo create a D7 version of this function
545
    throw new \Exception('Mail testing is not yet implemented for Drupal 7.');
546
  }
547
548
  /**
549
   * {@inheritdoc}
550
   */
551
  public function getMail() {
552
    // @todo create a D7 version of this function
553
    throw new \Exception('Mail testing is not yet implemented for Drupal 7.');
554
  }
555
556
  /**
557
   * {@inheritdoc}
558
   */
559
  public function clearMail() {
560
    // @todo create a D7 version of this function
561
    throw new \Exception('Mail testing is not yet implemented for Drupal 7.');
562
  }
563
564
  /**
565
   * {@inheritdoc}
566
   */
567
  public function sendMail($body, $subject = '', $to = '', $langcode = '') {
568
    // @todo create a D7 version of this function
569
    throw new \Exception('Mail testing is not yet implemented for Drupal 7.');
570
  }
571
572
}
573