These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 | use Behat\Behat\Context\Environment\InitializedContextEnvironment; |
||
9 | |||
10 | use Drupal\DrupalDriverManager; |
||
11 | use Drupal\DrupalExtension\DrupalParametersTrait; |
||
12 | use Drupal\DrupalExtension\Manager\DrupalAuthenticationManagerInterface; |
||
13 | use Drupal\DrupalExtension\Manager\DrupalUserManagerInterface; |
||
14 | |||
15 | use Drupal\DrupalExtension\Hook\Scope\AfterLanguageEnableScope; |
||
16 | use Drupal\DrupalExtension\Hook\Scope\AfterNodeCreateScope; |
||
17 | use Drupal\DrupalExtension\Hook\Scope\AfterTermCreateScope; |
||
18 | use Drupal\DrupalExtension\Hook\Scope\AfterUserCreateScope; |
||
19 | use Drupal\DrupalExtension\Hook\Scope\BaseEntityScope; |
||
20 | use Drupal\DrupalExtension\Hook\Scope\BeforeLanguageEnableScope; |
||
21 | use Drupal\DrupalExtension\Hook\Scope\BeforeNodeCreateScope; |
||
22 | use Drupal\DrupalExtension\Hook\Scope\BeforeUserCreateScope; |
||
23 | use Drupal\DrupalExtension\Hook\Scope\BeforeTermCreateScope; |
||
24 | use Drupal\DrupalExtension\Manager\FastLogoutInterface; |
||
25 | |||
26 | /** |
||
27 | * Provides the raw functionality for interacting with Drupal. |
||
28 | */ |
||
29 | class RawDrupalContext extends RawMinkContext implements DrupalAwareInterface |
||
30 | { |
||
31 | |||
32 | use DrupalParametersTrait; |
||
33 | |||
34 | /** |
||
35 | * Drupal driver manager. |
||
36 | * |
||
37 | * @var \Drupal\DrupalDriverManager |
||
38 | */ |
||
39 | private $drupal; |
||
40 | |||
41 | /** |
||
42 | * Event dispatcher object. |
||
43 | * |
||
44 | * @var \Behat\Testwork\Hook\HookDispatcher |
||
45 | */ |
||
46 | protected $dispatcher; |
||
47 | |||
48 | /** |
||
49 | * Drupal authentication manager. |
||
50 | * |
||
51 | * @var \Drupal\DrupalExtension\Manager\DrupalAuthenticationManagerInterface |
||
52 | */ |
||
53 | protected $authenticationManager; |
||
54 | |||
55 | /** |
||
56 | * Drupal user manager. |
||
57 | * |
||
58 | * @var \Drupal\DrupalExtension\Manager\DrupalUserManagerInterface |
||
59 | */ |
||
60 | protected $userManager; |
||
61 | |||
62 | /** |
||
63 | * Keep track of nodes so they can be cleaned up. |
||
64 | * |
||
65 | * @var array |
||
66 | */ |
||
67 | protected $nodes = array(); |
||
68 | |||
69 | /** |
||
70 | * Keep track of all terms that are created so they can easily be removed. |
||
71 | * |
||
72 | * @var array |
||
73 | */ |
||
74 | protected $terms = array(); |
||
75 | |||
76 | /** |
||
77 | * Keep track of any roles that are created so they can easily be removed. |
||
78 | * |
||
79 | * @var array |
||
80 | */ |
||
81 | protected $roles = array(); |
||
82 | |||
83 | /** |
||
84 | * Keep track of any languages that are created so they can easily be removed. |
||
85 | * |
||
86 | * @var array |
||
87 | */ |
||
88 | protected $languages = array(); |
||
89 | |||
90 | /** |
||
91 | * {@inheritDoc} |
||
92 | */ |
||
93 | public function setDrupal(DrupalDriverManager $drupal) |
||
94 | { |
||
95 | $this->drupal = $drupal; |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * {@inheritDoc} |
||
100 | */ |
||
101 | public function getDrupal() |
||
102 | { |
||
103 | return $this->drupal; |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * {@inheritDoc} |
||
108 | */ |
||
109 | public function setUserManager(DrupalUserManagerInterface $userManager) |
||
110 | { |
||
111 | $this->userManager = $userManager; |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * {@inheritdoc} |
||
116 | */ |
||
117 | public function getUserManager() |
||
118 | { |
||
119 | return $this->userManager; |
||
120 | } |
||
121 | |||
122 | /** |
||
123 | * {@inheritdoc} |
||
124 | */ |
||
125 | public function setAuthenticationManager(DrupalAuthenticationManagerInterface $authenticationManager) |
||
126 | { |
||
127 | $this->authenticationManager = $authenticationManager; |
||
128 | } |
||
129 | |||
130 | /** |
||
131 | * {@inheritdoc} |
||
132 | */ |
||
133 | public function getAuthenticationManager() |
||
134 | { |
||
135 | return $this->authenticationManager; |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * Magic setter. |
||
140 | */ |
||
141 | public function __set($name, $value) |
||
142 | { |
||
143 | switch ($name) { |
||
144 | case 'user': |
||
145 | trigger_error('Interacting directly with the RawDrupalContext::$user property has been deprecated. Use RawDrupalContext::getUserManager->setCurrentUser() instead.', E_USER_DEPRECATED); |
||
146 | // Set the user on the user manager service, so it is shared between all |
||
147 | // contexts. |
||
148 | $this->getUserManager()->setCurrentUser($value); |
||
149 | break; |
||
150 | |||
151 | case 'users': |
||
152 | trigger_error('Interacting directly with the RawDrupalContext::$users property has been deprecated. Use RawDrupalContext::getUserManager->addUser() instead.', E_USER_DEPRECATED); |
||
153 | // Set the user on the user manager service, so it is shared between all |
||
154 | // contexts. |
||
155 | if (empty($value)) { |
||
156 | $this->getUserManager()->clearUsers(); |
||
157 | } else { |
||
158 | foreach ($value as $user) { |
||
159 | $this->getUserManager()->addUser($user); |
||
160 | } |
||
161 | } |
||
162 | break; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * Magic getter. |
||
168 | */ |
||
169 | public function __get($name) |
||
170 | { |
||
171 | switch ($name) { |
||
172 | case 'user': |
||
173 | trigger_error('Interacting directly with the RawDrupalContext::$user property has been deprecated. Use RawDrupalContext::getUserManager->getCurrentUser() instead.', E_USER_DEPRECATED); |
||
174 | // Returns the current user from the user manager service. This is shared |
||
175 | // between all contexts. |
||
176 | return $this->getUserManager()->getCurrentUser(); |
||
177 | |||
178 | case 'users': |
||
179 | trigger_error('Interacting directly with the RawDrupalContext::$users property has been deprecated. Use RawDrupalContext::getUserManager->getUsers() instead.', E_USER_DEPRECATED); |
||
180 | // Returns the current user from the user manager service. This is shared |
||
181 | // between all contexts. |
||
182 | return $this->getUserManager()->getUsers(); |
||
183 | } |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * {@inheritdoc} |
||
188 | */ |
||
189 | public function setDispatcher(HookDispatcher $dispatcher) |
||
190 | { |
||
191 | $this->dispatcher = $dispatcher; |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Get active Drupal Driver. |
||
196 | * |
||
197 | * @return \Drupal\Driver\DrupalDriver |
||
198 | */ |
||
199 | public function getDriver($name = null) |
||
200 | { |
||
201 | return $this->getDrupal()->getDriver($name); |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Get driver's random generator. |
||
206 | */ |
||
207 | public function getRandom() |
||
208 | { |
||
209 | return $this->getDriver()->getRandom(); |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * Massage node values to match the expectations on different Drupal versions. |
||
214 | * |
||
215 | * @beforeNodeCreate |
||
216 | */ |
||
217 | public static function alterNodeParameters(BeforeNodeCreateScope $scope) |
||
218 | { |
||
219 | $node = $scope->getEntity(); |
||
220 | |||
221 | // Get the Drupal API version if available. This is not available when |
||
222 | // using e.g. the BlackBoxDriver or DrushDriver. |
||
223 | $api_version = null; |
||
224 | $driver = $scope->getContext()->getDrupal()->getDriver(); |
||
0 ignored issues
–
show
|
|||
225 | if ($driver instanceof \Drupal\Driver\DrupalDriver) { |
||
226 | $api_version = $scope->getContext()->getDrupal()->getDriver()->version; |
||
0 ignored issues
–
show
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\MailContext , Drupal\DrupalExtension\Context\MessageContext , Drupal\DrupalExtension\Context\RandomContext , Drupal\DrupalExtension\Context\RawDrupalContext , Drupal\DrupalExtension\Context\RawMailContext , 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
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
227 | } |
||
228 | |||
229 | // On Drupal 8 the timestamps should be in UNIX time. |
||
230 | switch ($api_version) { |
||
231 | case 8: |
||
232 | foreach (array('changed', 'created', 'revision_timestamp') as $field) { |
||
233 | if (!empty($node->$field) && !is_numeric($node->$field)) { |
||
234 | $node->$field = strtotime($node->$field); |
||
235 | } |
||
236 | } |
||
237 | break; |
||
238 | } |
||
239 | } |
||
240 | |||
241 | /** |
||
242 | * Remove any created nodes. |
||
243 | * |
||
244 | * @AfterScenario |
||
245 | */ |
||
246 | public function cleanNodes() |
||
247 | { |
||
248 | // Remove any nodes that were created. |
||
249 | foreach ($this->nodes as $node) { |
||
250 | $this->getDriver()->nodeDelete($node); |
||
251 | } |
||
252 | $this->nodes = array(); |
||
253 | } |
||
254 | |||
255 | /** |
||
256 | * Remove any created users. |
||
257 | * |
||
258 | * @AfterScenario |
||
259 | */ |
||
260 | public function cleanUsers() |
||
261 | { |
||
262 | // Remove any users that were created. |
||
263 | if ($this->userManager->hasUsers()) { |
||
264 | foreach ($this->userManager->getUsers() as $user) { |
||
265 | $this->getDriver()->userDelete($user); |
||
266 | } |
||
267 | $this->getDriver()->processBatch(); |
||
268 | $this->userManager->clearUsers(); |
||
269 | // If the authentication manager supports logout, no need to check if the user is logged in. |
||
270 | if ($this->getAuthenticationManager() instanceof FastLogoutInterface) { |
||
271 | $this->logout(true); |
||
272 | } elseif ($this->loggedIn()) { |
||
273 | $this->logout(); |
||
274 | } |
||
275 | } |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Remove any created terms. |
||
280 | * |
||
281 | * @AfterScenario |
||
282 | */ |
||
283 | public function cleanTerms() |
||
284 | { |
||
285 | // Remove any terms that were created. |
||
286 | foreach ($this->terms as $term) { |
||
287 | $this->getDriver()->termDelete($term); |
||
288 | } |
||
289 | $this->terms = array(); |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * Remove any created roles. |
||
294 | * |
||
295 | * @AfterScenario |
||
296 | */ |
||
297 | public function cleanRoles() |
||
298 | { |
||
299 | // Remove any roles that were created. |
||
300 | foreach ($this->roles as $rid) { |
||
301 | $this->getDriver()->roleDelete($rid); |
||
302 | } |
||
303 | $this->roles = array(); |
||
304 | } |
||
305 | |||
306 | /** |
||
307 | * Remove any created languages. |
||
308 | * |
||
309 | * @AfterScenario |
||
310 | */ |
||
311 | public function cleanLanguages() |
||
312 | { |
||
313 | // Delete any languages that were created. |
||
314 | foreach ($this->languages as $language) { |
||
315 | $this->getDriver()->languageDelete($language); |
||
316 | unset($this->languages[$language->langcode]); |
||
317 | } |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * Clear static caches. |
||
322 | * |
||
323 | * @AfterScenario @api |
||
324 | */ |
||
325 | public function clearStaticCaches() |
||
326 | { |
||
327 | $this->getDriver()->clearStaticCaches(); |
||
328 | } |
||
329 | |||
330 | /** |
||
331 | * Dispatch scope hooks. |
||
332 | * |
||
333 | * @param string $scope |
||
0 ignored issues
–
show
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 /**
* @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...
|
|||
334 | * The entity scope to dispatch. |
||
335 | * @param \stdClass $entity |
||
336 | * The entity. |
||
337 | */ |
||
338 | protected function dispatchHooks($scopeType, \stdClass $entity) |
||
339 | { |
||
340 | $fullScopeClass = 'Drupal\\DrupalExtension\\Hook\\Scope\\' . $scopeType; |
||
341 | $scope = new $fullScopeClass($this->getDrupal()->getEnvironment(), $this, $entity); |
||
342 | $callResults = $this->dispatcher->dispatchScopeHooks($scope); |
||
343 | |||
344 | // The dispatcher suppresses exceptions, throw them here if there are any. |
||
345 | foreach ($callResults as $result) { |
||
346 | if ($result->hasException()) { |
||
347 | $exception = $result->getException(); |
||
348 | throw $exception; |
||
349 | } |
||
350 | } |
||
351 | } |
||
352 | |||
353 | /** |
||
354 | * Create a node. |
||
355 | * |
||
356 | * @return object |
||
357 | * The created node. |
||
358 | */ |
||
359 | View Code Duplication | public function nodeCreate($node) |
|
0 ignored issues
–
show
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...
|
|||
360 | { |
||
361 | $this->dispatchHooks('BeforeNodeCreateScope', $node); |
||
362 | $this->parseEntityFields('node', $node); |
||
363 | $saved = $this->getDriver()->createNode($node); |
||
364 | $this->dispatchHooks('AfterNodeCreateScope', $saved); |
||
365 | $this->nodes[] = $saved; |
||
366 | return $saved; |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * Parses the field values and turns them into the format expected by Drupal. |
||
371 | * |
||
372 | * Multiple values in a single field must be separated by commas. Wrap the |
||
373 | * field value in double quotes in case it should contain a comma. |
||
374 | * |
||
375 | * Compound field properties are identified using a ':' operator, either in |
||
376 | * the column heading or in the cell. If multiple properties are present in a |
||
377 | * single cell, they must be separated using ' - ', and values should not |
||
378 | * contain ':' or ' - '. |
||
379 | * |
||
380 | * Possible formats for the values: |
||
381 | * A |
||
382 | * A, B, "a value, containing a comma" |
||
383 | * A - B |
||
384 | * x: A - y: B |
||
385 | * A - B, C - D, "E - F" |
||
386 | * x: A - y: B, x: C - y: D, "x: E - y: F" |
||
387 | * |
||
388 | * See field_handlers.feature for examples of usage. |
||
389 | * |
||
390 | * @param string $entity_type |
||
391 | * The entity type. |
||
392 | * @param \stdClass $entity |
||
393 | * An object containing the entity properties and fields as properties. |
||
394 | * |
||
395 | * @throws \Exception |
||
396 | * Thrown when a field name is invalid. |
||
397 | */ |
||
398 | public function parseEntityFields($entity_type, \stdClass $entity) |
||
399 | { |
||
400 | $multicolumn_field = ''; |
||
401 | $multicolumn_fields = array(); |
||
402 | |||
403 | foreach (clone $entity as $field => $field_value) { |
||
0 ignored issues
–
show
|
|||
404 | // Reset the multicolumn field if the field name does not contain a column. |
||
405 | if (strpos($field, ':') === false) { |
||
406 | $multicolumn_field = ''; |
||
407 | } // Start tracking a new multicolumn field if the field name contains a ':' |
||
408 | // which is preceded by at least 1 character. |
||
409 | elseif (strpos($field, ':', 1) !== false) { |
||
410 | list($multicolumn_field, $multicolumn_column) = explode(':', $field); |
||
411 | } // If a field name starts with a ':' but we are not yet tracking a |
||
412 | // multicolumn field we don't know to which field this belongs. |
||
413 | elseif (empty($multicolumn_field)) { |
||
414 | throw new \Exception('Field name missing for ' . $field); |
||
415 | } // Update the column name if the field name starts with a ':' and we are |
||
416 | // already tracking a multicolumn field. |
||
417 | else { |
||
418 | $multicolumn_column = substr($field, 1); |
||
419 | } |
||
420 | |||
421 | $is_multicolumn = $multicolumn_field && $multicolumn_column; |
||
0 ignored issues
–
show
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
Loading history...
|
|||
422 | $field_name = $multicolumn_field ?: $field; |
||
423 | if ($this->getDriver()->isField($entity_type, $field_name)) { |
||
424 | // Split up multiple values in multi-value fields. |
||
425 | $values = array(); |
||
426 | foreach (str_getcsv($field_value) as $key => $value) { |
||
427 | $value = trim($value); |
||
428 | $columns = $value; |
||
429 | // Split up field columns if the ' - ' separator is present. |
||
430 | if (strstr($value, ' - ') !== false) { |
||
431 | $columns = array(); |
||
432 | foreach (explode(' - ', $value) as $column) { |
||
433 | // Check if it is an inline named column. |
||
434 | if (!$is_multicolumn && strpos($column, ': ', 1) !== false) { |
||
435 | list ($key, $column) = explode(': ', $column); |
||
436 | $columns[$key] = $column; |
||
437 | } else { |
||
438 | $columns[] = $column; |
||
439 | } |
||
440 | } |
||
441 | } |
||
442 | // Use the column name if we are tracking a multicolumn field. |
||
443 | if ($is_multicolumn) { |
||
444 | $multicolumn_fields[$multicolumn_field][$key][$multicolumn_column] = $columns; |
||
445 | unset($entity->$field); |
||
446 | } else { |
||
447 | $values[] = $columns; |
||
448 | } |
||
449 | } |
||
450 | // Replace regular fields inline in the entity after parsing. |
||
451 | if (!$is_multicolumn) { |
||
452 | $entity->$field_name = $values; |
||
453 | // Don't specify any value if the step author has left it blank. |
||
454 | if ($field_value === '') { |
||
455 | unset($entity->$field_name); |
||
456 | } |
||
457 | } |
||
458 | } |
||
459 | } |
||
460 | |||
461 | // Add the multicolumn fields to the entity. |
||
462 | foreach ($multicolumn_fields as $field_name => $columns) { |
||
463 | // Don't specify any value if the step author has left it blank. |
||
464 | if (count(array_filter($columns, function ($var) { |
||
465 | return ($var !== ''); |
||
466 | })) > 0) { |
||
467 | $entity->$field_name = $columns; |
||
468 | } |
||
469 | } |
||
470 | } |
||
471 | |||
472 | /** |
||
473 | * Create a user. |
||
474 | * |
||
475 | * @return object |
||
476 | * The created user. |
||
477 | */ |
||
478 | public function userCreate($user) |
||
479 | { |
||
480 | $this->dispatchHooks('BeforeUserCreateScope', $user); |
||
481 | $this->parseEntityFields('user', $user); |
||
482 | $this->getDriver()->userCreate($user); |
||
483 | $this->dispatchHooks('AfterUserCreateScope', $user); |
||
484 | $this->userManager->addUser($user); |
||
485 | return $user; |
||
486 | } |
||
487 | |||
488 | /** |
||
489 | * Create a term. |
||
490 | * |
||
491 | * @return object |
||
492 | * The created term. |
||
493 | */ |
||
494 | View Code Duplication | public function termCreate($term) |
|
0 ignored issues
–
show
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...
|
|||
495 | { |
||
496 | $this->dispatchHooks('BeforeTermCreateScope', $term); |
||
497 | $this->parseEntityFields('taxonomy_term', $term); |
||
498 | $saved = $this->getDriver()->createTerm($term); |
||
499 | $this->dispatchHooks('AfterTermCreateScope', $saved); |
||
500 | $this->terms[] = $saved; |
||
501 | return $saved; |
||
502 | } |
||
503 | |||
504 | /** |
||
505 | * Creates a language. |
||
506 | * |
||
507 | * @param \stdClass $language |
||
508 | * An object with the following properties: |
||
509 | * - langcode: the langcode of the language to create. |
||
510 | * |
||
511 | * @return object|FALSE |
||
512 | * The created language, or FALSE if the language was already created. |
||
513 | */ |
||
514 | public function languageCreate(\stdClass $language) |
||
515 | { |
||
516 | $this->dispatchHooks('BeforeLanguageCreateScope', $language); |
||
517 | $language = $this->getDriver()->languageCreate($language); |
||
518 | if ($language) { |
||
519 | $this->dispatchHooks('AfterLanguageCreateScope', $language); |
||
520 | $this->languages[$language->langcode] = $language; |
||
521 | } |
||
522 | return $language; |
||
523 | } |
||
524 | |||
525 | /** |
||
526 | * Log-in the given user. |
||
527 | * |
||
528 | * @param \stdClass $user |
||
529 | * The user to log in. |
||
530 | */ |
||
531 | public function login(\stdClass $user) |
||
532 | { |
||
533 | $this->getAuthenticationManager()->logIn($user); |
||
534 | } |
||
535 | |||
536 | /** |
||
537 | * Logs the current user out. |
||
538 | * |
||
539 | * @param bool $fast |
||
540 | * Utilize direct logout by session if available. |
||
541 | */ |
||
542 | public function logout($fast = false) |
||
543 | { |
||
544 | if ($fast && $this->getAuthenticationManager() instanceof FastLogoutInterface) { |
||
545 | $this->getAuthenticationManager()->fastLogout(); |
||
546 | } else { |
||
547 | $this->getAuthenticationManager()->logOut(); |
||
548 | } |
||
549 | } |
||
550 | |||
551 | /** |
||
552 | * Determine if the a user is already logged in. |
||
553 | * |
||
554 | * @return boolean |
||
555 | * Returns TRUE if a user is logged in for this session. |
||
556 | */ |
||
557 | public function loggedIn() |
||
558 | { |
||
559 | return $this->getAuthenticationManager()->loggedIn(); |
||
560 | } |
||
561 | |||
562 | /** |
||
563 | * User with a given role is already logged in. |
||
564 | * |
||
565 | * @param string $role |
||
566 | * A single role, or multiple comma-separated roles in a single string. |
||
567 | * |
||
568 | * @return boolean |
||
569 | * Returns TRUE if the current logged in user has this role (or roles). |
||
570 | */ |
||
571 | public function loggedInWithRole($role) |
||
572 | { |
||
573 | return $this->loggedIn() && $this->getUserManager()->currentUserHasRole($role); |
||
574 | } |
||
575 | |||
576 | /** |
||
577 | * Returns the Behat context that corresponds with the given class name. |
||
578 | * |
||
579 | * This is inspired by InitializedContextEnvironment::getContext() but also |
||
580 | * returns subclasses of the given class name. This allows us to retrieve for |
||
581 | * example DrupalContext even if it is overridden in a project. |
||
582 | * |
||
583 | * @param string $class |
||
584 | * A fully namespaced class name. |
||
585 | * |
||
586 | * @return \Behat\Behat\Context\Context|false |
||
587 | * The requested context, or FALSE if the context is not registered. |
||
588 | * |
||
589 | * @throws \Exception |
||
590 | * Thrown when the environment is not yet initialized, meaning that contexts |
||
591 | * cannot yet be retrieved. |
||
592 | */ |
||
593 | protected function getContext($class) |
||
594 | { |
||
595 | /** @var InitializedContextEnvironment $environment */ |
||
596 | $environment = $this->drupal->getEnvironment(); |
||
597 | // Throw an exception if the environment is not yet initialized. To make |
||
598 | // sure state doesn't leak between test scenarios, the environment is |
||
599 | // reinitialized at the start of every scenario. If this code is executed |
||
600 | // before a test scenario starts (e.g. in a `@BeforeScenario` hook) then the |
||
601 | // contexts cannot yet be retrieved. |
||
602 | if (!$environment instanceof InitializedContextEnvironment) { |
||
603 | throw new \Exception('Cannot retrieve contexts when the environment is not yet initialized.'); |
||
604 | } |
||
605 | foreach ($environment->getContexts() as $context) { |
||
606 | if ($context instanceof $class) { |
||
607 | return $context; |
||
608 | } |
||
609 | } |
||
610 | |||
611 | return false; |
||
612 | } |
||
613 | } |
||
614 |
Let’s take a look at an example:
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
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: