KernelAwareInitializer::rebootKernel()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Behat Symfony2Extension
5
 *
6
 * (c) Konstantin Kudryashov <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Behat\Symfony2Extension\Context\Initializer;
13
14
use Behat\Behat\Context\Context;
15
use Behat\Behat\Context\Initializer\ContextInitializer;
16
use Behat\Behat\EventDispatcher\Event\ExampleTested;
17
use Behat\Behat\EventDispatcher\Event\ScenarioTested;
18
use Behat\Symfony2Extension\Context\KernelAwareContext;
19
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
20
use Symfony\Component\HttpKernel\KernelInterface;
21
22
/**
23
 * Kernel aware contexts initializer.
24
 * Sets Kernel instance to the KernelAware contexts.
25
 *
26
 * @author Konstantin Kudryashov <[email protected]>
27
 */
28
final class KernelAwareInitializer implements ContextInitializer, EventSubscriberInterface
29
{
30
    private $kernel;
31
32
    /**
33
     * Initializes initializer.
34
     *
35
     * @param KernelInterface $kernel
36
     */
37
    public function __construct(KernelInterface $kernel)
38
    {
39
        $this->kernel = $kernel;
40
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    public static function getSubscribedEvents()
46
    {
47
        return array(
48
            ScenarioTested::AFTER  => array('rebootKernel', -15),
49
            ExampleTested::AFTER   => array('rebootKernel', -15),
50
        );
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function initializeContext(Context $context)
57
    {
58
        if (!$context instanceof KernelAwareContext && !$this->usesKernelDictionary($context)) {
59
            return;
60
        }
61
62
        $context->setKernel($this->kernel);
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 setKernel() does only exist in the following implementations of said interface: Behat\Sf2DemoBundle\Feat...\Context\FeatureContext, Behat\Sf2DemoBundle\Features\Context\WebContext.

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...
63
    }
64
65
    /**
66
     * Reboots HttpKernel after each scenario.
67
     */
68
    public function rebootKernel()
69
    {
70
        $this->kernel->shutdown();
71
        $this->kernel->boot();
72
    }
73
74
    /**
75
     * Checks whether the context uses the KernelDictionary trait.
76
     *
77
     * @param Context $context
78
     *
79
     * @return boolean
80
     */
81
    private function usesKernelDictionary(Context $context)
82
    {
83
        $refl = new \ReflectionObject($context);
84
        if (method_exists($refl, 'getTraitNames')) {
85
            if (in_array('Behat\\Symfony2Extension\\Context\\KernelDictionary', $refl->getTraitNames())) {
86
                return true;
87
            }
88
        }
89
90
        return false;
91
    }
92
}
93