Completed
Pull Request — master (#114)
by
unknown
01:43
created

Drupal8::expandEntityBaseFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 3
1
<?php
2
3
namespace Drupal\Driver\Cores;
4
5
use Drupal\Core\DrupalKernel;
6
use Drupal\Core\Field\BaseFieldDefinition;
7
use Drupal\Driver\Exception\BootstrapException;
8
use Drupal\field\Entity\FieldStorageConfig;
9
use Drupal\language\Entity\ConfigurableLanguage;
10
use Drupal\node\Entity\Node;
11
use Drupal\node\NodeInterface;
12
use Drupal\Core\Entity\ContentEntityInterface;
13
use Drupal\taxonomy\Entity\Term;
14
use Drupal\taxonomy\TermInterface;
15
use Symfony\Component\HttpFoundation\Request;
16
17
/**
18
 * Drupal 8 core.
19
 */
20
class Drupal8 extends AbstractCore {
21
22
  /**
23
   * {@inheritdoc}
24
   */
25
  public function bootstrap() {
26
    // Validate, and prepare environment for Drupal bootstrap.
27
    if (!defined('DRUPAL_ROOT')) {
28
      define('DRUPAL_ROOT', $this->drupalRoot);
29
    }
30
31
    // Bootstrap Drupal.
32
    chdir(DRUPAL_ROOT);
33
    $autoloader = require DRUPAL_ROOT . '/autoload.php';
34
    require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
35
    $this->validateDrupalSite();
36
37
    $request = Request::createFromGlobals();
38
    $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
39
    $kernel->boot();
40
    $kernel->prepareLegacyRequest($request);
41
42
    // Initialise an anonymous session. required for the bootstrap.
43
    \Drupal::service('session_manager')->start();
44
  }
45
46
  /**
47
   * {@inheritdoc}
48
   */
49
  public function clearCache() {
50
    // Need to change into the Drupal root directory or the registry explodes.
51
    drupal_flush_all_caches();
52
  }
53
54
  /**
55
   * {@inheritdoc}
56
   */
57
  public function nodeCreate($node) {
58
    // Throw an exception if the node type is missing or does not exist.
59
    if (!isset($node->type) || !$node->type) {
60
      throw new \Exception("Cannot create content because it is missing the required property 'type'.");
61
    }
62
    $bundles = \Drupal::entityManager()->getBundleInfo('node');
63
    if (!in_array($node->type, array_keys($bundles))) {
64
      throw new \Exception("Cannot create content because provided content type '$node->type' does not exist.");
65
    }
66
    // Default status to 1 if not set.
67
    if (!isset($node->status)) {
68
      $node->status = 1;
69
    }
70
    // If 'author' is set, remap it to 'uid'.
71
    if (isset($node->author)) {
72
      $user = user_load_by_name($node->author);
73
      if ($user) {
74
        $node->uid = $user->id();
75
      }
76
    }
77
    $this->expandEntityFields('node', $node);
78
    $entity = entity_create('node', (array) $node);
79
    $entity->save();
80
81
    $node->nid = $entity->id();
82
83
    return $node;
84
  }
85
86
  /**
87
   * {@inheritdoc}
88
   */
89
  public function nodeDelete($node) {
90
    $node = $node instanceof NodeInterface ? $node : Node::load($node->nid);
0 ignored issues
show
Bug introduced by
The class Drupal\node\NodeInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
91
    if ($node instanceof NodeInterface) {
0 ignored issues
show
Bug introduced by
The class Drupal\node\NodeInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
92
      $node->delete();
93
    }
94
  }
95
96
  /**
97
   * {@inheritdoc}
98
   */
99
  public function runCron() {
100
    return \Drupal::service('cron')->run();
101
  }
102
103
  /**
104
   * {@inheritdoc}
105
   */
106
  public function userCreate(\stdClass $user) {
107
    $this->validateDrupalSite();
108
109
    // Default status to TRUE if not explicitly creating a blocked user.
110
    if (!isset($user->status)) {
111
      $user->status = 1;
112
    }
113
114
    // Clone user object, otherwise user_save() changes the password to the
115
    // hashed password.
116
    $this->expandEntityFields('user', $user);
117
    $account = entity_create('user', (array) $user);
118
    $account->save();
119
120
    // Store UID.
121
    $user->uid = $account->id();
122
  }
123
124
  /**
125
   * {@inheritdoc}
126
   */
127
  public function roleCreate(array $permissions) {
128
    // Generate a random, lowercase machine name.
129
    $rid = strtolower($this->random->name(8, TRUE));
130
131
    // Generate a random label.
132
    $name = trim($this->random->name(8, TRUE));
133
134
    // Convert labels to machine names.
135
    $this->convertPermissions($permissions);
136
137
    // Check the all the permissions strings are valid.
138
    $this->checkPermissions($permissions);
139
140
    // Create new role.
141
    $role = entity_create('user_role', array(
142
      'id' => $rid,
143
      'label' => $name,
144
    ));
145
    $result = $role->save();
146
147
    if ($result === SAVED_NEW) {
148
      // Grant the specified permissions to the role, if any.
149
      if (!empty($permissions)) {
150
        user_role_grant_permissions($role->id(), $permissions);
151
      }
152
      return $role->id();
153
    }
154
155
    throw new \RuntimeException(sprintf('Failed to create a role with "%s" permission(s).', implode(', ', $permissions)));
156
  }
157
158
  /**
159
   * {@inheritdoc}
160
   */
161
  public function roleDelete($role_name) {
162
    $role = user_role_load($role_name);
163
164
    if (!$role) {
165
      throw new \RuntimeException(sprintf('No role "%s" exists.', $role_name));
166
    }
167
168
    $role->delete();
169
  }
170
171
  /**
172
   * {@inheritdoc}
173
   */
174
  public function processBatch() {
175
    $this->validateDrupalSite();
176
    $batch =& batch_get();
177
    $batch['progressive'] = FALSE;
178
    batch_process();
179
  }
180
181
  /**
182
   * Retrieve all permissions.
183
   *
184
   * @return array
185
   *   Array of all defined permissions.
186
   */
187
  protected function getAllPermissions() {
188
    $permissions = &drupal_static(__FUNCTION__);
189
190
    if (!isset($permissions)) {
191
      $permissions = \Drupal::service('user.permissions')->getPermissions();
192
    }
193
194
    return $permissions;
195
  }
196
197
  /**
198
   * Convert any permission labels to machine name.
199
   *
200
   * @param array &$permissions
201
   *   Array of permission names.
202
   */
203
  protected function convertPermissions(array &$permissions) {
204
    $all_permissions = $this->getAllPermissions();
205
206
    foreach ($all_permissions as $name => $definition) {
207
      $key = array_search($definition['title'], $permissions);
208
      if (FALSE !== $key) {
209
        $permissions[$key] = $name;
210
      }
211
    }
212
  }
213
214
  /**
215
   * Check to make sure that the array of permissions are valid.
216
   *
217
   * @param array $permissions
218
   *   Permissions to check.
219
   */
220
  protected function checkPermissions(array &$permissions) {
221
    $available = array_keys($this->getAllPermissions());
222
223
    foreach ($permissions as $permission) {
224
      if (!in_array($permission, $available)) {
225
        throw new \RuntimeException(sprintf('Invalid permission "%s".', $permission));
226
      }
227
    }
228
  }
229
230
  /**
231
   * {@inheritdoc}
232
   */
233
  public function userDelete(\stdClass $user) {
234
    user_cancel(array(), $user->uid, 'user_cancel_delete');
235
  }
236
237
  /**
238
   * {@inheritdoc}
239
   */
240
  public function userAddRole(\stdClass $user, $role_name) {
241
    // Allow both machine and human role names.
242
    $roles = user_role_names();
243
    $id = array_search($role_name, $roles);
244
    if (FALSE !== $id) {
245
      $role_name = $id;
246
    }
247
248
    if (!$role = user_role_load($role_name)) {
249
      throw new \RuntimeException(sprintf('No role "%s" exists.', $role_name));
250
    }
251
252
    $account = \user_load($user->uid);
253
    $account->addRole($role->id());
254
    $account->save();
255
  }
256
257
  /**
258
   * {@inheritdoc}
259
   */
260
  public function validateDrupalSite() {
261
    if ('default' !== $this->uri) {
262
      // Fake the necessary HTTP headers that Drupal needs:
263
      $drupal_base_url = parse_url($this->uri);
264
      // If there's no url scheme set, add http:// and re-parse the url
265
      // so the host and path values are set accurately.
266
      if (!array_key_exists('scheme', $drupal_base_url)) {
267
        $drupal_base_url = parse_url($this->uri);
268
      }
269
      // Fill in defaults.
270
      $drupal_base_url += array(
271
        'path' => NULL,
272
        'host' => NULL,
273
        'port' => NULL,
274
      );
275
      $_SERVER['HTTP_HOST'] = $drupal_base_url['host'];
276
277
      if ($drupal_base_url['port']) {
278
        $_SERVER['HTTP_HOST'] .= ':' . $drupal_base_url['port'];
279
      }
280
      $_SERVER['SERVER_PORT'] = $drupal_base_url['port'];
281
282
      if (array_key_exists('path', $drupal_base_url)) {
283
        $_SERVER['PHP_SELF'] = $drupal_base_url['path'] . '/index.php';
284
      }
285
      else {
286
        $_SERVER['PHP_SELF'] = '/index.php';
287
      }
288
    }
289
    else {
290
      $_SERVER['HTTP_HOST'] = 'default';
291
      $_SERVER['PHP_SELF'] = '/index.php';
292
    }
293
294
    $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] = $_SERVER['PHP_SELF'];
295
    $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
296
    $_SERVER['REQUEST_METHOD']  = NULL;
297
298
    $_SERVER['SERVER_SOFTWARE'] = NULL;
299
    $_SERVER['HTTP_USER_AGENT'] = NULL;
300
301
    $conf_path = DrupalKernel::findSitePath(Request::createFromGlobals());
302
    $conf_file = $this->drupalRoot . "/$conf_path/settings.php";
303
    if (!file_exists($conf_file)) {
304
      throw new BootstrapException(sprintf('Could not find a Drupal settings.php file at "%s"', $conf_file));
305
    }
306
  }
307
308
  /**
309
   * {@inheritdoc}
310
   */
311
  public function termCreate(\stdClass $term) {
312
    $term->vid = $term->vocabulary_machine_name;
313
    $this->expandEntityFields('taxonomy_term', $term);
314
    $entity = Term::create((array) $term);
315
    $entity->save();
316
317
    $term->tid = $entity->id();
318
    return $term;
319
  }
320
321
  /**
322
   * {@inheritdoc}
323
   */
324
  public function termDelete(\stdClass $term) {
325
    $term = $term instanceof TermInterface ? $term : Term::load($term->tid);
0 ignored issues
show
Bug introduced by
The class Drupal\taxonomy\TermInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
326
    if ($term instanceof TermInterface) {
0 ignored issues
show
Bug introduced by
The class Drupal\taxonomy\TermInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
327
      $term->delete();
328
    }
329
  }
330
331
  /**
332
   * {@inheritdoc}
333
   */
334
  public function getModuleList() {
335
    return array_keys(\Drupal::moduleHandler()->getModuleList());
336
  }
337
338
  /**
339
   * {@inheritdoc}
340
   */
341
  public function getExtensionPathList() {
342
    $paths = array();
343
344
    // Get enabled modules.
345
    foreach (\Drupal::moduleHandler()->getModuleList() as $module) {
346
      $paths[] = $this->drupalRoot . DIRECTORY_SEPARATOR . $module->getPath();
347
    }
348
349
    return $paths;
350
  }
351
352
  /**
353
   * Expands specified base fields on the entity object.
354
   *
355
   * @param string $entity_type
356
   *   The entity type for which to return the field types.
357
   * @param \stdClass $entity
358
   *   Entity object.
359
   * @param array $base_fields
360
   *   Base fields to be expanded in addition to user defined fields.
361
   */
362
  public function expandEntityBaseFields($entity_type, \stdClass $entity, $base_fields) {
363
    $this->expandEntityFields($entity_type, $entity, $base_fields);
364
  }
365
366
  /**
367
   * {@inheritdoc}
368
   */
369
  public function getEntityFieldTypes($entity_type, $base_fields = array()) {
370
    $return = array();
371
    $fields = \Drupal::entityManager()->getFieldStorageDefinitions($entity_type);
372
    foreach ($fields as $field_name => $field) {
373
      if ($this->isField($entity_type, $field_name)
374
        || (in_array($field_name, $base_fields) && $this->isBaseField($entity_type, $field_name))) {
375
        $return[$field_name] = $field->getType();
376
      }
377
    }
378
    return $return;
379
  }
380
381
  /**
382
   * {@inheritdoc}
383
   */
384
  public function isField($entity_type, $field_name) {
385
    $fields = \Drupal::entityManager()->getFieldStorageDefinitions($entity_type);
386
    return (isset($fields[$field_name]) && $fields[$field_name] instanceof FieldStorageConfig);
0 ignored issues
show
Bug introduced by
The class Drupal\field\Entity\FieldStorageConfig does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
387
  }
388
389
  /**
390
   * {@inheritdoc}
391
   */
392
  public function isBaseField($entity_type, $field_name) {
393
    $fields = \Drupal::entityManager()->getFieldStorageDefinitions($entity_type);
394
    return (isset($fields[$field_name]) && $fields[$field_name] instanceof BaseFieldDefinition);
0 ignored issues
show
Bug introduced by
The class Drupal\Core\Field\BaseFieldDefinition does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
395
  }
396
397
  /**
398
   * {@inheritdoc}
399
   */
400
  public function languageCreate(\stdClass $language) {
401
    $langcode = $language->langcode;
402
403
    // Enable a language only if it has not been enabled already.
404
    if (!ConfigurableLanguage::load($langcode)) {
405
      $created_language = ConfigurableLanguage::createFromLangcode($language->langcode);
406
      if (!$created_language) {
407
        throw new InvalidArgumentException("There is no predefined language with langcode '{$langcode}'.");
408
      }
409
      $created_language->save();
410
      return $language;
411
    }
412
413
    return FALSE;
414
  }
415
416
  /**
417
   * {@inheritdoc}
418
   */
419
  public function languageDelete(\stdClass $language) {
420
    $configurable_language = ConfigurableLanguage::load($language->langcode);
421
    $configurable_language->delete();
422
  }
423
424
  /**
425
   * {@inheritdoc}
426
   */
427
  public function clearStaticCaches() {
428
    drupal_static_reset();
429
    \Drupal::service('cache_tags.invalidator')->resetChecksums();
430
  }
431
432
  /**
433
   * {@inheritdoc}
434
   */
435
  public function configGet($name, $key = '') {
436
    return \Drupal::config($name)->get($key);
437
  }
438
439
  /**
440
   * {@inheritdoc}
441
   */
442
  public function configSet($name, $key, $value) {
443
    \Drupal::configFactory()->getEditable($name)
444
      ->set($key, $value)
445
      ->save();
446
  }
447
448
  /**
449
   * {@inheritdoc}
450
   */
451
  public function entityCreate($entity_type, $entity) {
452
    // If the bundle field is empty, put the inferred bundle value in it.
453
    $bundle_key = \Drupal::entityManager()->getDefinition($entity_type)->getKey('bundle');
454
    if (!isset($entity->$bundle_key) && isset($entity->step_bundle)) {
455
      $entity->$bundle_key = $entity->step_bundle;
456
    }
457
458
    // Throw an exception if a bundle is specified but does not exist.
459
    if (isset($entity->$bundle_key) && ($entity->$bundle_key !== NULL)) {
460
      $bundles = \Drupal::entityManager()->getBundleInfo($entity_type);
461
      if (!in_array($entity->$bundle_key, array_keys($bundles))) {
462
        throw new \Exception("Cannot create entity because provided bundle '$entity->$bundle_key' does not exist.");
463
      }
464
    }
465
    if (empty($entity_type)) {
466
      throw new \Exception("You must specify an entity type to create an entity.");
467
    }
468
469
    $this->expandEntityFields($entity_type, $entity);
0 ignored issues
show
Documentation introduced by
$entity is of type array, but the function expects a object<stdClass>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
470
    $createdEntity = entity_create($entity_type, (array) $entity);
471
    $createdEntity->save();
472
473
    $entity->id = $createdEntity->id();
474
475
    return $entity;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $entity; (array) is incompatible with the return type declared by the interface Drupal\Driver\Cores\CoreInterface::entityCreate of type Drupal\Core\Entity\EntityInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
476
  }
477
478
  /**
479
   * {@inheritdoc}
480
   */
481
  public function entityDelete($entity_type, $entity) {
482
    $entity = $entity instanceof ContentEntityInterface ? $entity : entity_load($entity_type, $entity->id);
0 ignored issues
show
Bug introduced by
The class Drupal\Core\Entity\ContentEntityInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
483
    if ($entity instanceof ContentEntityInterface) {
0 ignored issues
show
Bug introduced by
The class Drupal\Core\Entity\ContentEntityInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
484
      $entity->delete();
485
    }
486
  }
487
488
}
489