Passed
Pull Request — master (#2608)
by Kévin
03:18
created

Client::request()   C

Complexity

Conditions 13
Paths 108

Size

Total Lines 64
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 35
nc 108
nop 3
dl 0
loc 64
rs 6.55
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\Test;
15
16
use Symfony\Bundle\FrameworkBundle\Client as FrameworkBundleClient;
17
use Symfony\Component\DependencyInjection\ContainerInterface;
18
use Symfony\Component\HttpClient\HttpClientTrait;
19
use Symfony\Component\HttpKernel\KernelInterface;
20
use Symfony\Component\HttpKernel\Profiler\Profile as HttpProfile;
21
use Symfony\Contracts\HttpClient\HttpClientInterface;
22
use Symfony\Contracts\HttpClient\ResponseInterface;
23
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
24
25
/**
26
 * Convenient test client that makes requests to a Kernel object.
27
 *
28
 * @experimental
29
 *
30
 * @author Kévin Dunglas <[email protected]>
31
 */
32
final class Client implements HttpClientInterface
33
{
34
    public const OPTIONS_DEFAULT = [
35
        'query' => [],                                      // string[] - associative array of query string values to merge with the request's URL
36
        'headers' => ['accept' => ['application/ld+json']], // iterable|string[]|string[][] - headers names provided as keys or as part of values
37
        'body' => '',                                       // array|string|resource|\Traversable|\Closure - the callback SHOULD yield a string
38
        'json' => null,                                     // array|\JsonSerializable - when set, implementations MUST set the "body" option to
39
        //   the JSON-encoded value and set the "content-type" headers to a JSON-compatible
40
        'base_uri' => 'http://example.com',                 // string - the URI to resolve relative URLs, following rules in RFC 3986, section 2
41
        'auth' => null,                                     // string - a username:password enabling HTTP Basic authentication (RFC 7617)
42
        'bearer' => null,                                   // string - a token enabling HTTP Bearer authorization (RFC 6750)
43
    ];
44
45
    use HttpClientTrait;
46
47
    private $fwbClient;
48
49
    public function __construct(FrameworkBundleClient $fwbClient)
50
    {
51
        $this->fwbClient = $fwbClient;
52
        $fwbClient->followRedirects(false);
53
    }
54
55
    /**
56
     * @see Client::OPTIONS_DEFAULTS for available options
57
     *
58
     * {@inheritdoc}
59
     */
60
    public function request(string $method, string $url, array $options = []): ResponseInterface
61
    {
62
        if (isset($options['body'])) {
63
            if (isset($options['headers'])) {
64
                $options['headers'] = self::normalizeHeaders($options['headers']);
65
            }
66
67
            $json = false;
68
            if (!isset($options['headers']['content-type'][0])) {
69
                // Content-Type default to JSON-LD if a body is set, but no Content-Type is defined
70
                $options['headers']['content-type'] = $options['headers']['content-type'] ?? ['application/ld+json'];
71
                $json = true;
72
            }
73
74
            if (
75
                (\is_array($options['body']) || $options['body'] instanceof \JsonSerializable) &&
76
                (
77
                    $json ||
78
                    preg_match('/\bjson\b/i', $options['headers']['content-type'][0])
79
                )
80
            ) {
81
                // Encode the JSON
82
                $options['json'] = $options['body'];
83
            }
84
        }
85
86
        // TODO: remove when https://github.com/symfony/symfony/pull/30547 will be merged
87
        if (isset($options['bearer']) && \is_string($options['bearer'])) {
88
            $options['headers']['authorization'] = ['Bearer '.$options['bearer']];
89
        }
90
91
        $basic = $options['auth'] ?? null;
92
        [$url, $options] = $this->prepareRequest($method, $url, $options, self::OPTIONS_DEFAULT);
93
94
        $server = [];
95
        // Convert headers to a $_SERVER-like array
96
        foreach ($options['headers'] as $key => $value) {
97
            if ('content-type' === $key) {
98
                $server['CONTENT_TYPE'] = $value[0] ?? '';
99
100
                continue;
101
            }
102
103
            // BrowserKit doesn't support setting several headers with the same name
104
            $server['HTTP_'.strtoupper(str_replace('-', '_', $key))] = $value[0] ?? '';
105
        }
106
107
        if ($basic) {
108
            $credentials = explode(':', $basic, 2);
109
            $server['PHP_AUTH_USER'] = $credentials[0];
110
            $server['PHP_AUTH_PW'] = $credentials[1] ?? '';
111
        }
112
113
        $info = [
114
            'redirect_count' => 0,
115
            'redirect_url' => null,
116
            'http_method' => $method,
117
            'start_time' => microtime(true),
118
            'data' => $options['data'] ?? null,
119
            'url' => $url,
120
        ];
121
        $this->fwbClient->request($method, implode('', $url), [], [], $server, $options['body'] ?? null);
122
123
        return new Response($this->fwbClient->getResponse(), $this->fwbClient->getInternalResponse(), $info);
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function stream($responses, float $timeout = null): ResponseStreamInterface
130
    {
131
        throw new \LogicException('Not implemented yet');
132
    }
133
134
    /**
135
     * Gets the underlying test client.
136
     */
137
    public function getFrameworkBundleClient(): FrameworkBundleClient
138
    {
139
        return $this->fwbClient;
140
    }
141
142
    // The following methods are proxy methods for FrameworkBundleClient's ones
143
144
    /**
145
     * Returns the container.
146
     *
147
     * @return ContainerInterface|null Returns null when the Kernel has been shutdown or not started yet
148
     */
149
    public function getContainer()
150
    {
151
        return $this->fwbClient->getContainer();
152
    }
153
154
    /**
155
     * Returns the kernel.
156
     *
157
     * @return KernelInterface
158
     */
159
    public function getKernel()
160
    {
161
        return $this->fwbClient->getKernel();
162
    }
163
164
    /**
165
     * Gets the profile associated with the current Response.
166
     *
167
     * @return HttpProfile|false A Profile instance
168
     */
169
    public function getProfile()
170
    {
171
        return $this->fwbClient->getProfile();
172
    }
173
174
    /**
175
     * Enables the profiler for the very next request.
176
     *
177
     * If the profiler is not enabled, the call to this method does nothing.
178
     */
179
    public function enableProfiler()
180
    {
181
        $this->fwbClient->enableProfiler();
182
    }
183
184
    /**
185
     * Disables kernel reboot between requests.
186
     *
187
     * By default, the Client reboots the Kernel for each request. This method
188
     * allows to keep the same kernel across requests.
189
     */
190
    public function disableReboot()
191
    {
192
        $this->fwbClient->disableReboot();
193
    }
194
195
    /**
196
     * Enables kernel reboot between requests.
197
     */
198
    public function enableReboot()
199
    {
200
        $this->fwbClient->enableReboot();
201
    }
202
}
203