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

Client::request()   C

Complexity

Conditions 12
Paths 54

Size

Total Lines 56
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 30
nc 54
nop 3
dl 0
loc 56
rs 6.9666
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
        'bearer' => null,                                   // string - sets a corresponding Authorization token of the Bearer type
42
    ];
43
44
    use HttpClientTrait;
45
46
    private $fwbClient;
47
48
    public function __construct(FrameworkBundleClient $fwbClient)
49
    {
50
        $this->fwbClient = $fwbClient;
51
        $fwbClient->followRedirects(false);
52
    }
53
54
    /**
55
     * @see Client::OPTIONS_DEFAULTS for available options
56
     *
57
     * {@inheritdoc}
58
     */
59
    public function request(string $method, string $url, array $options = []): ResponseInterface
60
    {
61
        if (isset($options['body'])) {
62
            if (isset($options['headers'])) {
63
                $options['headers'] = self::normalizeHeaders($options['headers']);
64
            }
65
66
            $json = false;
67
            if (!isset($options['headers']['content-type'][0])) {
68
                // Content-Type default to JSON-LD if a body is set, but no Content-Type is defined
69
                $options['headers']['content-type'] = $options['headers']['content-type'] ?? ['application/ld+json'];
70
                $json = true;
71
            }
72
73
            if (
74
                (\is_array($options['body']) || $options['body'] instanceof \JsonSerializable) &&
75
                (
76
                    $json ||
77
                    false !== preg_match('#^application/(?:.+\+)?json$#', $options['headers']['content-type'][0])
78
                )
79
            ) {
80
                // Encode the JSON
81
                $options['json'] = $options['body'];
82
            }
83
        }
84
85
        if (isset($options['bearer']) && \is_string($options['bearer'])) {
86
            $options['headers']['authorization'] = ['Bearer '.$options['bearer']];
87
        }
88
89
        [$url, $options] = $this->prepareRequest($method, $url, $options, self::OPTIONS_DEFAULT);
90
91
        $server = [];
92
        // Convert headers to a $_SERVER-like array
93
        foreach ($options['headers'] as $key => $value) {
94
            if ('content-type' === strtolower($key)) {
95
                $server['CONTENT_TYPE'] = $value[0] ?? '';
96
97
                continue;
98
            }
99
100
            // BrowserKit doesn't support setting several headers with the same name
101
            $server['HTTP_'.strtoupper(str_replace('-', '_', $key))] = $value[0] ?? '';
102
        }
103
104
        $info = [
105
            'redirect_count' => 0,
106
            'redirect_url' => null,
107
            'http_method' => $method,
108
            'start_time' => microtime(true),
109
            'data' => $options['data'] ?? null,
110
            'url' => $url,
111
        ];
112
        $this->fwbClient->request($method, implode('', $url), [], [], $server, $options['body'] ?? null);
113
114
        return new Response($this->fwbClient->getResponse(), $this->fwbClient->getInternalResponse(), $info);
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function stream($responses, float $timeout = null): ResponseStreamInterface
121
    {
122
        throw new \LogicException('Not implemented yet');
123
    }
124
125
    /**
126
     * Gets the underlying test client.
127
     */
128
    public function getFrameworkBundleClient(): FrameworkBundleClient
129
    {
130
        return $this->fwbClient;
131
    }
132
133
    // The following methods are proxy methods for FrameworkBundleClient's ones
134
135
    /**
136
     * Returns the container.
137
     *
138
     * @return ContainerInterface|null Returns null when the Kernel has been shutdown or not started yet
139
     */
140
    public function getContainer()
141
    {
142
        return $this->fwbClient->getContainer();
143
    }
144
145
    /**
146
     * Returns the kernel.
147
     *
148
     * @return KernelInterface
149
     */
150
    public function getKernel()
151
    {
152
        return $this->fwbClient->getKernel();
153
    }
154
155
    /**
156
     * Gets the profile associated with the current Response.
157
     *
158
     * @return HttpProfile|false A Profile instance
159
     */
160
    public function getProfile()
161
    {
162
        return $this->fwbClient->getProfile();
163
    }
164
165
    /**
166
     * Enables the profiler for the very next request.
167
     *
168
     * If the profiler is not enabled, the call to this method does nothing.
169
     */
170
    public function enableProfiler()
171
    {
172
        $this->fwbClient->enableProfiler();
173
    }
174
175
    /**
176
     * Disables kernel reboot between requests.
177
     *
178
     * By default, the Client reboots the Kernel for each request. This method
179
     * allows to keep the same kernel across requests.
180
     */
181
    public function disableReboot()
182
    {
183
        $this->fwbClient->disableReboot();
184
    }
185
186
    /**
187
     * Enables kernel reboot between requests.
188
     */
189
    public function enableReboot()
190
    {
191
        $this->fwbClient->enableReboot();
192
    }
193
}
194