Passed
Pull Request — master (#2608)
by Antoine
04:39
created

Response.php$3 ➔ getBrowserKitResponse()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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 ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Exception\ClientException;
17
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Exception\RedirectionException;
18
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Exception\ServerException;
19
use Symfony\Component\BrowserKit\Response as BrowserKitResponse;
20
use Symfony\Component\HttpClient\Exception\JsonException;
21
use Symfony\Component\HttpFoundation\Response as HttpFoundationResponse;
22
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
23
use Symfony\Contracts\HttpClient\ResponseInterface;
24
25
/**
26
 * HTTP Response.
27
 *
28
 * @internal
29
 *
30
 * Partially copied from \Symfony\Component\HttpClient\Response\ResponseTrait
31
 *
32
 * @author Kévin Dunglas <[email protected]>
33
 */
34
final class Response implements ResponseInterface
35
{
36
    private $httpFoundationResponse;
37
    private $browserKitResponse;
38
    private $info;
39
    private $content;
40
    private $jsonData;
41
42
    public function __construct(HttpFoundationResponse $httpFoundationResponse, BrowserKitResponse $browserKitResponse, array $info)
43
    {
44
        $this->httpFoundationResponse = $httpFoundationResponse;
45
        $this->browserKitResponse = $browserKitResponse;
46
47
        $this->headers = $httpFoundationResponse->headers->all();
48
        $this->content = $httpFoundationResponse->getContent();
49
        $this->info = $info + [
50
            'http_code' => $httpFoundationResponse->getStatusCode(),
51
            'error' => null,
52
            'raw_headers' => $this->headers,
0 ignored issues
show
Bug Best Practice introduced by
The property headers does not exist on ApiPlatform\Core\Bridge\...ny\Bundle\Test\Response. Did you maybe forget to declare it?
Loading history...
53
        ];
54
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59
    public function getInfo(string $type = null)
60
    {
61
        if ($type) {
62
            return $this->info[$type] ?? null;
63
        }
64
65
        return $this->info;
66
    }
67
68
    /**
69
     * Checks the status, and try to extract message if appropriate.
70
     */
71
    private function checkStatusCode()
72
    {
73
        // TODO: use https://github.com/symfony/symfony/pull/30559 instead
74
        $message = 'An error '.$this->info['http_code'].' occured.';
75
        if (isset($this->headers['content-type'][0]) && preg_match('/\bjson\b/i', $this->headers['content-type'][0])) {
0 ignored issues
show
Bug Best Practice introduced by
The property headers does not exist on ApiPlatform\Core\Bridge\...ny\Bundle\Test\Response. Did you maybe forget to declare it?
Loading history...
76
            if ($json = json_decode($this->content, true)) {
77
                // Try to extract the error message from Hydra or RFC 7807 error structures
78
                $message = $json['hydra:description'] ?? $json['hydra:title'] ?? $json['detail'] ?? $json['title'] ?? $message;
79
            }
80
        }
81
82
        if (500 <= $this->info['http_code']) {
83
            throw new ServerException($message, $this->info['http_code']);
84
        }
85
86
        if (400 <= $this->info['http_code']) {
87
            throw new ClientException($message, $this->info['http_code']);
88
        }
89
90
        if (300 <= $this->info['http_code']) {
91
            throw new RedirectionException($message, $this->info['http_code']);
92
        }
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98
    public function getContent(bool $throw = true): string
99
    {
100
        if ($throw) {
101
            $this->checkStatusCode();
102
        }
103
104
        return $this->content;
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function getStatusCode(): int
111
    {
112
        return $this->info['http_code'];
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    public function getHeaders(bool $throw = true): array
119
    {
120
        if ($throw) {
121
            $this->checkStatusCode();
122
        }
123
124
        return $this->headers;
0 ignored issues
show
Bug Best Practice introduced by
The property headers does not exist on ApiPlatform\Core\Bridge\...ny\Bundle\Test\Response. Did you maybe forget to declare it?
Loading history...
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public function toArray(bool $throw = true): array
131
    {
132
        if (null !== $this->jsonData) {
133
            return $this->jsonData;
134
        }
135
136
        if ('' === $content = $this->getContent($throw)) {
137
            throw new class(sprintf('Response body is empty.', $contentType)) extends \Exception implements TransportExceptionInterface {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $contentType does not exist. Did you maybe mean $content?
Loading history...
138
            };
139
        }
140
141
        $contentType = $this->headers['content-type'][0] ?? 'application/json';
0 ignored issues
show
Bug Best Practice introduced by
The property headers does not exist on ApiPlatform\Core\Bridge\...ny\Bundle\Test\Response. Did you maybe forget to declare it?
Loading history...
142
143
        if (!preg_match('/\bjson\b/i', $contentType)) {
144
            throw new class(sprintf('Response content-type is "%s" while a JSON-compatible one was expected.', $contentType)) extends \JsonException implements TransportExceptionInterface {
145
            };
146
        }
147
148
        try {
149
            $content = json_decode($content, true, 512, JSON_BIGINT_AS_STRING | (\PHP_VERSION_ID >= 70300 ? JSON_THROW_ON_ERROR : 0));
150
        } catch (\JsonException $e) {
151
            throw new class($e->getMessage(), $e->getCode()) extends \JsonException implements TransportExceptionInterface {
152
            };
153
        }
154
155
        if (\PHP_VERSION_ID < 70300 && JSON_ERROR_NONE !== json_last_error()) {
156
            throw new JsonException(json_last_error_msg(), json_last_error());
157
        }
158
159
        if (!\is_array($content)) {
160
            throw new class(sprintf('JSON content was expected to decode to an array, %s returned.', \gettype($content))) extends \JsonException implements TransportExceptionInterface {
161
            };
162
        }
163
164
        return $this->jsonData = $content;
165
    }
166
167
    /**
168
     * Returns the internal HttpKernel response.
169
     */
170
    public function getKernelResponse(): HttpFoundationResponse
171
    {
172
        return $this->httpFoundationResponse;
173
    }
174
175
    /**
176
     * Returns the internal BrowserKit reponse.
177
     */
178
    public function getBrowserKitResponse(): BrowserKitResponse
179
    {
180
        return $this->browserKitResponse;
181
    }
182
}
183