Completed
Pull Request — master (#164)
by Vincent
03:00
created

BrowserKit::resetHttpHeaders()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 0
1
<?php
2
3
namespace Sanpi\Behatch\HttpCall\Request;
4
5
use Behat\Mink\Driver\Goutte\Client as GoutteClient;
6
use Behat\Mink\Mink;
7
use Symfony\Component\BrowserKit\Client as BrowserKitClient;
8
use Symfony\Component\HttpFoundation\File\UploadedFile;
9
10
class BrowserKit
11
{
12
    protected $mink;
13
14
    public function __construct(Mink $mink)
15
    {
16
        $this->mink = $mink;
17
    }
18
19
    public function getMethod()
20
    {
21
        return $this->getRequest()
22
            ->getMethod();
23
    }
24
25
    public function getUri()
26
    {
27
        return $this->getRequest()
28
            ->getUri();
29
    }
30
31
    public function getServer()
32
    {
33
        return $this->getRequest()
34
            ->getServer();
35
    }
36
37
    public function getParameters()
38
    {
39
        return $this->getRequest()
40
            ->getParameters();
41
    }
42
43
    protected function getRequest()
44
    {
45
        $client = $this->mink->getSession()->getDriver()->getClient();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Mink\Driver\DriverInterface as the method getClient() does only exist in the following implementations of said interface: Behat\Mink\Driver\BrowserKitDriver, Behat\Mink\Driver\GoutteDriver.

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...
46
        // BC layer for BrowserKit 2.2.x and older
47
        if (method_exists($client, 'getInternalRequest')) {
48
            $request = $client->getInternalRequest();
49
        } else {
50
            $request = $client->getRequest();
51
        }
52
        return $request;
53
    }
54
55
    public function getContent()
56
    {
57
        return $this->mink->getSession()->getPage()->getContent();
58
    }
59
60
    public function send($method, $url, $parameters = [], $files = [], $content = null, $headers = [])
61
    {
62
        foreach ($files as $originalName => &$file) {
63
            $file = new UploadedFile($file, $originalName);
64
        }
65
66
        $client = $this->mink->getSession()->getDriver()->getClient();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Mink\Driver\DriverInterface as the method getClient() does only exist in the following implementations of said interface: Behat\Mink\Driver\BrowserKitDriver, Behat\Mink\Driver\GoutteDriver.

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...
67
68
        $client->followRedirects(false);
69
        $client->request($method, $url, $parameters, $files, $headers, $content);
70
        $client->followRedirects(true);
71
        $this->resetHttpHeaders();
72
73
        return $this->mink->getSession()->getPage();
74
    }
75
76
    public function setHttpHeader($name, $value)
77
    {
78
        $client = $this->mink->getSession()->getDriver()->getClient();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Mink\Driver\DriverInterface as the method getClient() does only exist in the following implementations of said interface: Behat\Mink\Driver\BrowserKitDriver, Behat\Mink\Driver\GoutteDriver.

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...
79
        // Goutte\Client
80
        if (method_exists($client, 'setHeader')) {
81
            $client->setHeader($name, $value);
82
        } else {
83
            // Symfony\Component\BrowserKit\Client
84
85
            /* taken from Behat\Mink\Driver\BrowserKitDriver::setRequestHeader */
86
            $contentHeaders = array('CONTENT_LENGTH' => true, 'CONTENT_MD5' => true, 'CONTENT_TYPE' => true);
87
            $name = str_replace('-', '_', strtoupper($name));
88
89
            // CONTENT_* are not prefixed with HTTP_ in PHP when building $_SERVER
90
            if (!isset($contentHeaders[$name])) {
91
                $name = 'HTTP_' . $name;
92
            }
93
            /* taken from Behat\Mink\Driver\BrowserKitDriver::setRequestHeader */
94
95
            $client->setServerParameter($name, $value);
96
        }
97
    }
98
99
    public function getHttpHeaders()
100
    {
101
        return array_change_key_case(
102
            $this->mink->getSession()->getResponseHeaders(),
103
            CASE_LOWER
104
        );
105
    }
106
107
    public function getHttpHeader($name)
108
    {
109
        $name = strtolower($name);
110
        $headers = $this->getHttpHeaders();
111
112
        if (isset($headers[$name])) {
113
            if (is_array($headers[$name])) {
114
                $value = implode(', ', $headers[$name]);
115
            }
116
            else {
117
                $value = $headers[$name];
118
            }
119
        }
120
        else {
121
            throw new \OutOfBoundsException(
122
                "The header '$name' doesn't exist"
123
            );
124
        }
125
        return $value;
126
    }
127
128
    protected function resetHttpHeaders()
129
    {
130
        /** @var GoutteClient|BrowserKitClient $client */
131
        $client = $this->mink->getSession()->getDriver()->getClient();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Mink\Driver\DriverInterface as the method getClient() does only exist in the following implementations of said interface: Behat\Mink\Driver\BrowserKitDriver, Behat\Mink\Driver\GoutteDriver.

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...
132
133
        $client->setServerParameters([]);
134
        if ($client instanceof GoutteClient) {
135
            $client->restart();
136
        }
137
    }
138
}
139