Completed
Pull Request — master (#300)
by
unknown
02:13
created

RawDrupalContext::entityCreate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
rs 9.4285
cc 1
eloc 10
nc 1
nop 2
1
<?php
2
3
namespace Drupal\DrupalExtension\Context;
4
5
use Behat\MinkExtension\Context\RawMinkContext;
6
use Behat\Mink\Exception\DriverException;
7
use Behat\Testwork\Hook\HookDispatcher;
8
9
use Drupal\DrupalDriverManager;
10
11
use Drupal\DrupalExtension\Hook\Scope\AfterLanguageEnableScope;
12
use Drupal\DrupalExtension\Hook\Scope\AfterNodeCreateScope;
13
use Drupal\DrupalExtension\Hook\Scope\AfterTermCreateScope;
14
use Drupal\DrupalExtension\Hook\Scope\AfterUserCreateScope;
15
use Drupal\DrupalExtension\Hook\Scope\AfterEntityCreateScope;
16
use Drupal\DrupalExtension\Hook\Scope\BaseEntityScope;
17
use Drupal\DrupalExtension\Hook\Scope\BeforeLanguageEnableScope;
18
use Drupal\DrupalExtension\Hook\Scope\BeforeNodeCreateScope;
19
use Drupal\DrupalExtension\Hook\Scope\BeforeUserCreateScope;
20
use Drupal\DrupalExtension\Hook\Scope\BeforeTermCreateScope;
21
use Drupal\DrupalExtension\Hook\Scope\BeforeEntityCreateScope;
22
23
/**
24
 * Provides the raw functionality for interacting with Drupal.
25
 */
26
class RawDrupalContext extends RawMinkContext implements DrupalAwareInterface {
27
28
  /**
29
   * Drupal driver manager.
30
   *
31
   * @var \Drupal\DrupalDriverManager
32
   */
33
  private $drupal;
34
35
  /**
36
   * Test parameters.
37
   *
38
   * @var array
39
   */
40
  private $drupalParameters;
41
42
  /**
43
   * Event dispatcher object.
44
   *
45
   * @var \Behat\Testwork\Hook\HookDispatcher
46
   */
47
  protected $dispatcher;
48
49
  /**
50
   * Keep track of nodes so they can be cleaned up.
51
   *
52
   * @var array
53
   */
54
  protected $nodes = array();
55
56
  /**
57
   * Current authenticated user.
58
   *
59
   * A value of FALSE denotes an anonymous user.
60
   *
61
   * @var \stdClass|bool
62
   */
63
  public $user = FALSE;
64
65
  /**
66
   * Keep track of all users that are created so they can easily be removed.
67
   *
68
   * @var array
69
   */
70
  protected $users = array();
71
72
  /**
73
   * Keep track of all terms that are created so they can easily be removed.
74
   *
75
   * @var array
76
   */
77
  protected $terms = array();
78
79
  /**
80
   * Keep track of any roles that are created so they can easily be removed.
81
   *
82
   * @var array
83
   */
84
  protected $roles = array();
85
86
  /**
87
   * Keep track of any languages that are created so they can easily be removed.
88
   *
89
   * @var array
90
   */
91
  protected $languages = array();
92
93
  /**
94
   * Keep track of any entities that are created so they can easily be removed.
95
   *
96
   * @var array
97
   */
98
  protected $entities = array();
99
100
  /**
101
   * {@inheritDoc}
102
   */
103
  public function setDrupal(DrupalDriverManager $drupal) {
104
    $this->drupal = $drupal;
105
  }
106
107
  /**
108
   * {@inheritDoc}
109
   */
110
  public function getDrupal() {
111
    return $this->drupal;
112
  }
113
114
  /**
115
   * {@inheritDoc}
116
   */
117
  public function setDispatcher(HookDispatcher $dispatcher) {
118
    $this->dispatcher = $dispatcher;
119
  }
120
121
  /**
122
   * Set parameters provided for Drupal.
123
   */
124
  public function setDrupalParameters(array $parameters) {
125
    $this->drupalParameters = $parameters;
126
  }
127
128
  /**
129
   * Returns a specific Drupal parameter.
130
   *
131
   * @param string $name
132
   *   Parameter name.
133
   *
134
   * @return mixed
135
   */
136
  public function getDrupalParameter($name) {
137
    return isset($this->drupalParameters[$name]) ? $this->drupalParameters[$name] : NULL;
138
  }
139
140
  /**
141
   * Returns a specific Drupal text value.
142
   *
143
   * @param string $name
144
   *   Text value name, such as 'log_out', which corresponds to the default 'Log
145
   *   out' link text.
146
   * @throws \Exception
147
   * @return
148
   */
149
  public function getDrupalText($name) {
150
    $text = $this->getDrupalParameter('text');
151
    if (!isset($text[$name])) {
152
      throw new \Exception(sprintf('No such Drupal string: %s', $name));
153
    }
154
    return $text[$name];
155
  }
156
157
  /**
158
   * Returns a specific css selector.
159
   *
160
   * @param $name
161
   *   string CSS selector name
162
   */
163
  public function getDrupalSelector($name) {
164
    $text = $this->getDrupalParameter('selectors');
165
    if (!isset($text[$name])) {
166
      throw new \Exception(sprintf('No such selector configured: %s', $name));
167
    }
168
    return $text[$name];
169
  }
170
171
  /**
172
   * Get active Drupal Driver.
173
   *
174
   * @return \Drupal\Driver\DrupalDriver
175
   */
176
  public function getDriver($name = NULL) {
177
    return $this->getDrupal()->getDriver($name);
178
  }
179
180
  /**
181
   * Get driver's random generator.
182
   */
183
  public function getRandom() {
184
    return $this->getDriver()->getRandom();
185
  }
186
187
  /**
188
   * Massage node values to match the expectations on different Drupal versions.
189
   *
190
   * @beforeNodeCreate
191
   */
192
  public function alterNodeParameters(BeforeNodeCreateScope $scope) {
193
    $node = $scope->getEntity();
194
195
    // Get the Drupal API version if available. This is not available when
196
    // using e.g. the BlackBoxDriver or DrushDriver.
197
    $api_version = NULL;
198
    $driver = $scope->getContext()->getDrupal()->getDriver();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Behat\Context\Context as the method getDrupal() does only exist in the following implementations of said interface: Drupal\DrupalExtension\Context\ConfigContext, Drupal\DrupalExtension\Context\DrupalContext, Drupal\DrupalExtension\C...xt\DrupalSubContextBase, Drupal\DrupalExtension\Context\DrushContext, Drupal\DrupalExtension\Context\EntityContext, Drupal\DrupalExtension\Context\MessageContext, Drupal\DrupalExtension\Context\RawDrupalContext, FeatureContext, FooFoo.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
199
    if ($driver instanceof \Drupal\Driver\DrupalDriver) {
200
      $api_version = $scope->getContext()->getDrupal()->getDriver()->version;
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Behat\Context\Context as the method getDrupal() does only exist in the following implementations of said interface: Drupal\DrupalExtension\Context\ConfigContext, Drupal\DrupalExtension\Context\DrupalContext, Drupal\DrupalExtension\C...xt\DrupalSubContextBase, Drupal\DrupalExtension\Context\DrushContext, Drupal\DrupalExtension\Context\EntityContext, Drupal\DrupalExtension\Context\MessageContext, Drupal\DrupalExtension\Context\RawDrupalContext, FeatureContext, FooFoo.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
201
    }
202
203
    // On Drupal 8 the timestamps should be in UNIX time.
204
    switch ($api_version) {
205
      case 8:
206
        foreach (array('changed', 'created', 'revision_timestamp') as $field) {
207
          if (!empty($node->$field) && !is_numeric($node->$field)) {
208
            $node->$field = strtotime($node->$field);
209
          }
210
        }
211
      break;
212
    }
213
  }
214
215
  /**
216
   * Remove any created nodes.
217
   *
218
   * @AfterScenario
219
   */
220
  public function cleanNodes() {
221
    // Remove any nodes that were created.
222
    foreach ($this->nodes as $node) {
223
      $this->getDriver()->nodeDelete($node);
224
    }
225
    $this->nodes = array();
226
  }
227
228
  /**
229
   * Remove any created users.
230
   *
231
   * @AfterScenario
232
   */
233
  public function cleanUsers() {
234
    // Remove any users that were created.
235
    if (!empty($this->users)) {
236
      foreach ($this->users as $user) {
237
        $this->getDriver()->userDelete($user);
238
      }
239
      $this->getDriver()->processBatch();
240
      $this->users = array();
241
      $this->user = FALSE;
242
      if ($this->loggedIn()) {
243
        $this->logout();
244
      }
245
    }
246
  }
247
248
  /**
249
   * Remove any created terms.
250
   *
251
   * @AfterScenario
252
   */
253
  public function cleanTerms() {
254
    // Remove any terms that were created.
255
    foreach ($this->terms as $term) {
256
      $this->getDriver()->termDelete($term);
257
    }
258
    $this->terms = array();
259
  }
260
261
  /**
262
   * Remove any created roles.
263
   *
264
   * @AfterScenario
265
   */
266
  public function cleanRoles() {
267
    // Remove any roles that were created.
268
    foreach ($this->roles as $rid) {
269
      $this->getDriver()->roleDelete($rid);
270
    }
271
    $this->roles = array();
272
  }
273
274
  /**
275
   * Remove any created languages.
276
   *
277
   * @AfterScenario
278
   */
279
  public function cleanLanguages() {
280
    // Delete any languages that were created.
281
    foreach ($this->languages as $language) {
282
      $this->getDriver()->languageDelete($language);
283
      unset($this->languages[$language->langcode]);
284
    }
285
  }
286
287
  /**
288
   * Clear static caches.
289
   *
290
   * @AfterScenario @api
291
   */
292
  public function clearStaticCaches() {
293
    $this->getDriver()->clearStaticCaches();
294
  }
295
296
  /**
297
   * Dispatch scope hooks.
298
   *
299
   * @param string $scope
0 ignored issues
show
Bug introduced by
There is no parameter named $scope. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
300
   *   The entity scope to dispatch.
301
   * @param \stdClass $entity
302
   *   The entity.
303
   */
304
  protected function dispatchHooks($scopeType, \stdClass $entity) {
305
    $fullScopeClass = 'Drupal\\DrupalExtension\\Hook\\Scope\\' . $scopeType;
306
    $scope = new $fullScopeClass($this->getDrupal()->getEnvironment(), $this, $entity);
307
    $callResults = $this->dispatcher->dispatchScopeHooks($scope);
308
309
    // The dispatcher suppresses exceptions, throw them here if there are any.
310
    foreach ($callResults as $result) {
311
      if ($result->hasException()) {
312
        $exception = $result->getException();
313
        throw $exception;
314
      }
315
    }
316
  }
317
318
  /**
319
   * Create a node.
320
   *
321
   * @return object
322
   *   The created node.
323
   */
324 View Code Duplication
  public function nodeCreate($node) {
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...
325
    $this->dispatchHooks('BeforeNodeCreateScope', $node);
326
    $this->parseEntityFields('node', $node);
327
    $saved = $this->getDriver()->createNode($node);
328
    $this->dispatchHooks('AfterNodeCreateScope', $saved);
329
    $this->nodes[] = $saved;
330
    return $saved;
331
  }
332
333
  /**
334
   * Parse multi-value fields. Possible formats:
335
   *    A, B, C
336
   *    A - B, C - D, E - F
337
   *
338
   * @param string $entity_type
339
   *   The entity type.
340
   * @param \stdClass $entity
341
   *   An object containing the entity properties and fields as properties.
342
   */
343
  public function parseEntityFields($entity_type, \stdClass $entity) {
344
    $multicolumn_field = '';
345
    $multicolumn_fields = array();
346
347
    foreach (clone $entity as $field => $field_value) {
0 ignored issues
show
Bug introduced by
The expression clone $entity of type object<stdClass> is not traversable.
Loading history...
348
      // Reset the multicolumn field if the field name does not contain a column.
349
      if (strpos($field, ':') === FALSE) {
350
        $multicolumn_field = '';
351
      }
352
      // Start tracking a new multicolumn field if the field name contains a ':'
353
      // which is preceded by at least 1 character.
354
      elseif (strpos($field, ':', 1) !== FALSE) {
355
        list($multicolumn_field, $multicolumn_column) = explode(':', $field);
356
      }
357
      // If a field name starts with a ':' but we are not yet tracking a
358
      // multicolumn field we don't know to which field this belongs.
359
      elseif (empty($multicolumn_field)) {
360
        throw new \Exception('Field name missing for ' . $field);
361
      }
362
      // Update the column name if the field name starts with a ':' and we are
363
      // already tracking a multicolumn field.
364
      else {
365
        $multicolumn_column = substr($field, 1);
366
      }
367
368
      $is_multicolumn = $multicolumn_field && $multicolumn_column;
0 ignored issues
show
Bug introduced by
The variable $multicolumn_column does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
369
      $field_name = $multicolumn_field ?: $field;
370
      if ($this->getDriver()->isField($entity_type, $field_name)) {
371
        // Split up multiple values in multi-value fields.
372
        $values = array();
373
        foreach (explode(', ', $field_value) as $key => $value) {
374
          $columns = $value;
375
          // Split up field columns if the ' - ' separator is present.
376
          if (strstr($value, ' - ') !== FALSE) {
377
            $columns = array();
378
            foreach (explode(' - ', $value) as $column) {
379
              // Check if it is an inline named column.
380
              if (!$is_multicolumn && strpos($column, ': ', 1) !== FALSE) {
381
                list ($key, $column) = explode(': ', $column);
382
                $columns[$key] = $column;
383
              }
384
              else {
385
                $columns[] = $column;
386
              }
387
            }
388
          }
389
          // Use the column name if we are tracking a multicolumn field.
390
          if ($is_multicolumn) {
391
            $multicolumn_fields[$multicolumn_field][$key][$multicolumn_column] = $columns;
392
            unset($entity->$field);
393
          }
394
          else {
395
            $values[] = $columns;
396
          }
397
        }
398
        // Replace regular fields inline in the entity after parsing.
399
        if (!$is_multicolumn) {
400
          $entity->$field_name = $values;
401
        }
402
      }
403
    }
404
405
    // Add the multicolumn fields to the entity.
406
    foreach ($multicolumn_fields as $field_name => $columns) {
407
      $entity->$field_name = $columns;
408
    }
409
  }
410
411
  /**
412
   * Create a user.
413
   *
414
   * @return object
415
   *   The created user.
416
   */
417 View Code Duplication
  public function userCreate($user) {
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...
418
    $this->dispatchHooks('BeforeUserCreateScope', $user);
419
    $this->parseEntityFields('user', $user);
420
    $this->getDriver()->userCreate($user);
421
    $this->dispatchHooks('AfterUserCreateScope', $user);
422
    $this->users[$user->name] = $this->user = $user;
423
    return $user;
424
  }
425
426
  /**
427
   * Create a term.
428
   *
429
   * @return object
430
   *   The created term.
431
   */
432 View Code Duplication
  public function termCreate($term) {
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...
433
    $this->dispatchHooks('BeforeTermCreateScope', $term);
434
    $this->parseEntityFields('taxonomy_term', $term);
435
    $saved = $this->getDriver()->createTerm($term);
436
    $this->dispatchHooks('AfterTermCreateScope', $saved);
437
    $this->terms[] = $saved;
438
    return $saved;
439
  }
440
441
  /**
442
   * Creates a language.
443
   *
444
   * @param \stdClass $language
445
   *   An object with the following properties:
446
   *   - langcode: the langcode of the language to create.
447
   *
448
   * @return object|FALSE
449
   *   The created language, or FALSE if the language was already created.
450
   */
451
  public function languageCreate(\stdClass $language) {
452
    $this->dispatchHooks('BeforeLanguageCreateScope', $language);
453
    $language = $this->getDriver()->languageCreate($language);
454
    if ($language) {
455
      $this->dispatchHooks('AfterLanguageCreateScope', $language);
456
      $this->languages[$language->langcode] = $language;
457
    }
458
    return $language;
459
  }
460
461
  /**
462
   * Log-in the current user.
463
   */
464
  public function login() {
465
    // Check if logged in.
466
    if ($this->loggedIn()) {
467
      $this->logout();
468
    }
469
470
    if (!$this->user) {
471
      throw new \Exception('Tried to login without a user.');
472
    }
473
474
    $this->getSession()->visit($this->locatePath('/user'));
475
    $element = $this->getSession()->getPage();
476
    $element->fillField($this->getDrupalText('username_field'), $this->user->name);
477
    $element->fillField($this->getDrupalText('password_field'), $this->user->pass);
478
    $submit = $element->findButton($this->getDrupalText('log_in'));
479
    if (empty($submit)) {
480
      throw new \Exception(sprintf("No submit button at %s", $this->getSession()->getCurrentUrl()));
481
    }
482
483
    // Log in.
484
    $submit->click();
485
486
    if (!$this->loggedIn()) {
487
      if (isset($this->user->role)) {
488
        throw new \Exception(sprintf("Unable to determine if logged in because 'log_out' link cannot be found for user '%s' with role '%s'", $this->user->name, $this->user->role));
489
      }
490
      else {
491
        throw new \Exception(sprintf("Unable to determine if logged in because 'log_out' link cannot be found for user '%s'", $this->user->name));
492
      }
493
    }
494
  }
495
496
  /**
497
   * Logs the current user out.
498
   */
499
  public function logout() {
500
    $this->getSession()->visit($this->locatePath('/user/logout'));
501
  }
502
503
  /**
504
   * Determine if the a user is already logged in.
505
   *
506
   * @return boolean
507
   *   Returns TRUE if a user is logged in for this session.
508
   */
509
  public function loggedIn() {
510
    $session = $this->getSession();
511
    $page = $session->getPage();
512
513
    // Look for a css selector to determine if a user is logged in.
514
    // Default is the logged-in class on the body tag.
515
    // Which should work with almost any theme.
516
    try {
517
      if ($page->has('css', $this->getDrupalSelector('logged_in_selector'))) {
518
        return TRUE;
519
      }
520
    } catch (DriverException $e) {
521
      // This test may fail if the driver did not load any site yet.
522
    }
523
524
    // Some themes do not add that class to the body, so lets check if the
525
    // login form is displayed on /user/login.
526
    $session->visit($this->locatePath('/user/login'));
527
    if (!$page->has('css', $this->getDrupalSelector('login_form_selector'))) {
528
      return TRUE;
529
    }
530
531
    $session->visit($this->locatePath('/'));
532
533
    // As a last resort, if a logout link is found, we are logged in. While not
534
    // perfect, this is how Drupal SimpleTests currently work as well.
535
    return $page->findLink($this->getDrupalText('log_out'));
536
  }
537
538
  /**
539
   * User with a given role is already logged in.
540
   *
541
   * @param string $role
542
   *   A single role, or multiple comma-separated roles in a single string.
543
   *
544
   * @return boolean
545
   *   Returns TRUE if the current logged in user has this role (or roles).
546
   */
547
  public function loggedInWithRole($role) {
548
    return $this->loggedIn() && $this->user && isset($this->user->role) && $this->user->role == $role;
549
  }
550
551
  /**
552
   * Create an entity.
553
   *
554
   * @return object
555
   *   The created entity.
556
   */
557
  public function entityCreate($entity_type, $entity) {
558
    // We want hooks to know the entity type, and to be able to modify the entity fields,
559
    // but we don't want to try to parse or save the entity_type as if it were a field
560
    $entity->entity_type = $entity_type;
561
    $this->dispatchHooks('BeforeEntityCreateScope', $entity);
562
    unset($entity->entity_type);
563
    $this->parseEntityFields($entity_type, $entity);
564
    $saved = $this->getDriver()->createEntity($entity_type, $entity);
0 ignored issues
show
Bug introduced by
The method createEntity() does not seem to exist on object<Drupal\Driver\DrupalDriver>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
565
    $saved->entity_type = $entity_type;
566
    $this->dispatchHooks('AfterEntityCreateScope', $saved);
567
    $this->entities[] = $saved;
568
    return $saved;
569
  }
570
571
  /**
572
   * Remove any content entities created by entityCreate(),
573
   * but not those created by nodeCreate(), termCreate() or userCreate().
574
   *
575
   * @AfterScenario
576
   */
577
  public function cleanEntities() {
578
    foreach ($this->entities as $entity) {
579
      $this->getDriver()->entityDelete($entity->entity_type, $entity);
0 ignored issues
show
Bug introduced by
The method entityDelete() does not seem to exist on object<Drupal\Driver\DrupalDriver>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
580
    }
581
    $this->entities = array();
582
  }
583
584
}
585