Completed
Push — master ( 158f00...4ee9ec )
by San
06:17 queued 02:55
created

BrowserKit::setHttpHeader()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.2
c 0
b 0
f 0
cc 3
eloc 10
nc 3
nop 2
1
<?php
2
3
namespace Behatch\HttpCall\Request;
4
5
use Behat\Mink\Mink;
6
use Symfony\Component\HttpFoundation\File\UploadedFile;
7
8
class BrowserKit
9
{
10
    protected $mink;
11
12
    public function __construct(Mink $mink)
13
    {
14
        $this->mink = $mink;
15
    }
16
17
    public function getMethod()
18
    {
19
        return $this->getRequest()
20
            ->getMethod();
21
    }
22
23
    public function getUri()
24
    {
25
        return $this->getRequest()
26
            ->getUri();
27
    }
28
29
    public function getServer()
30
    {
31
        return $this->getRequest()
32
            ->getServer();
33
    }
34
35
    public function getParameters()
36
    {
37
        return $this->getRequest()
38
            ->getParameters();
39
    }
40
41
    protected function getRequest()
42
    {
43
        $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...
44
        // BC layer for BrowserKit 2.2.x and older
45
        if (method_exists($client, 'getInternalRequest')) {
46
            $request = $client->getInternalRequest();
47
        } else {
48
            $request = $client->getRequest();
49
        }
50
        return $request;
51
    }
52
53
    public function getContent()
54
    {
55
        return $this->mink->getSession()->getPage()->getContent();
56
    }
57
58
    public function send($method, $url, $parameters = [], $files = [], $content = null, $headers = [])
59
    {
60
        foreach ($files as $originalName => &$file) {
61
            if (is_string($file)) {
62
                $file = new UploadedFile($file, $originalName);
63
            }
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
72
        return $this->mink->getSession()->getPage();
73
    }
74
75
    public function setHttpHeader($name, $value)
76
    {
77
        $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...
78
        // Goutte\Client
79
        if (method_exists($client, 'setHeader')) {
80
            $client->setHeader($name, $value);
81
        } else {
82
            // Symfony\Component\BrowserKit\Client
83
84
            /* taken from Behat\Mink\Driver\BrowserKitDriver::setRequestHeader */
85
            $contentHeaders = array('CONTENT_LENGTH' => true, 'CONTENT_MD5' => true, 'CONTENT_TYPE' => true);
86
            $name = str_replace('-', '_', strtoupper($name));
87
88
            // CONTENT_* are not prefixed with HTTP_ in PHP when building $_SERVER
89
            if (!isset($contentHeaders[$name])) {
90
                $name = 'HTTP_' . $name;
91
            }
92
            /* taken from Behat\Mink\Driver\BrowserKitDriver::setRequestHeader */
93
94
            $client->setServerParameter($name, $value);
95
        }
96
    }
97
98
    public function getHttpHeaders()
99
    {
100
        return array_change_key_case(
101
            $this->mink->getSession()->getResponseHeaders(),
102
            CASE_LOWER
103
        );
104
    }
105
106
    public function getHttpHeader($name)
107
    {
108
        $name = strtolower($name);
109
        $headers = $this->getHttpHeaders();
110
111
        if (isset($headers[$name])) {
112
            if (is_array($headers[$name])) {
113
                $value = implode(', ', $headers[$name]);
114
            } else {
115
                $value = $headers[$name];
116
            }
117
        } else {
118
            throw new \OutOfBoundsException(
119
                "The header '$name' doesn't exist"
120
            );
121
        }
122
        return $value;
123
    }
124
}
125