AbstractApi::processTransferException()   B
last analyzed

Complexity

Conditions 9
Paths 9

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 8.0555
c 0
b 0
f 0
cc 9
nc 9
nop 1
1
<?php
2
3
namespace Skobkin\Bundle\PointToolsBundle\Service\Api;
4
5
use GuzzleHttp\ClientInterface;
6
use GuzzleHttp\Exception\TransferException;
7
use JMS\Serializer\{DeserializationContext, SerializerInterface};
8
use Psr\Http\Message\{ResponseInterface, StreamInterface};
9
use Psr\Log\LoggerInterface;
10
use Skobkin\Bundle\PointToolsBundle\Exception\Api\{ForbiddenException, NetworkException, NotFoundException, ServerProblemException, UnauthorizedException};
11
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
12
13
abstract class AbstractApi
14
{
15
    /**
16
     * @var ClientInterface HTTP-client from Guzzle
17
     */
18
    protected $client;
19
20
    /**
21
     * @var SerializerInterface
22
     */
23
    protected $serializer;
24
25
    /**
26
     * @var LoggerInterface
27
     */
28
    protected $logger;
29
30
    /**
31
     * @var string Authentication token for API
32
     */
33
    protected $authToken;
34
35
    /**
36
     * @var string CSRF-token for API
37
     */
38
    protected $csRfToken;
39
40
41
    public function __construct(ClientInterface $httpClient, SerializerInterface $serializer, LoggerInterface $logger)
42
    {
43
        $this->client = $httpClient;
44
        $this->serializer = $serializer;
0 ignored issues
show
Documentation Bug introduced by
It seems like $serializer of type object<JMS\Serializer\SerializerInterface> is incompatible with the declared type object<SerializerInterface> of property $serializer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
45
        $this->logger = $logger;
46
    }
47
48
    /**
49
     * Make GET request and return DTO objects
50
     *
51
     * @return array|object
52
     */
53
    public function getGetJsonData(string $path, array $parameters = [], string $type, DeserializationContext $context = null)
54
    {
55
        return $this->serializer->deserialize(
56
            $this->getGetResponseBody($path, $parameters),
57
            $type,
58
            'json',
59
            $context
60
        );
61
    }
62
63
    /**
64
     * Make POST request and return DTO objects
65
     *
66
     * @return array|object
67
     */
68
    public function getPostJsonData(string $path, array $parameters = [], string $type, DeserializationContext $context = null)
69
    {
70
        return $this->serializer->deserialize(
71
            $this->getPostResponseBody($path, $parameters),
72
            $type,
73
            'json',
74
            $context
75
        );
76
    }
77
78
    /**
79
     * Make GET request and return response body
80
     */
81
    public function getGetResponseBody($path, array $parameters = []): StreamInterface
82
    {
83
        return $this->sendGetRequest($path, $parameters)->getBody();
84
    }
85
86
    /**
87
     * Make POST request and return response body
88
     */
89
    public function getPostResponseBody(string $path, array $parameters = []): StreamInterface
90
    {
91
        return $this->sendPostRequest($path, $parameters)->getBody();
92
    }
93
94
    /**
95
     * @param string $path Request path
96
     * @param array $parameters Key => Value array of query parameters
97
     *
98
     * @return ResponseInterface
99
     *
100
     * @throws NetworkException
101
     */
102
    private function sendGetRequest(string $path, array $parameters = []): ResponseInterface
103
    {
104
        $this->logger->debug('Sending GET request', ['path' => $path, 'parameters' => $parameters]);
105
106
        return $this->sendRequest('GET', $path, ['query' => $parameters]);
107
    }
108
109
    /**
110
     * @param string $path Request path
111
     * @param array $parameters Key => Value array of request data
112
     *
113
     * @return ResponseInterface
114
     *
115
     * @throws NetworkException
116
     */
117
    private function sendPostRequest(string $path, array $parameters = []): ResponseInterface
118
    {
119
        $this->logger->debug('Sending POST request', ['path' => $path, 'parameters' => $parameters]);
120
121
        return $this->sendRequest('POST', $path, ['form_params' => $parameters]);
122
    }
123
124
    private function sendRequest(string $method, string $path, array $parameters): ResponseInterface
125
    {
126
        try {
127
            $response = $this->client->request($method, $path, $parameters);
128
129
            $this->checkResponse($response);
130
131
            return $response;
132
        } catch (TransferException $e) {
133
            $this->processTransferException($e);
134
            
135
            throw new NetworkException('Request error', $e->getCode(), $e);
136
        }
137
    }
138
139
    /**
140
     * @todo refactor with $this->checkResponse()
141
     *
142
     * @param \Exception $e
143
     *
144
     * @throws ForbiddenException
145
     * @throws NotFoundException
146
     * @throws ServerProblemException
147
     * @throws UnauthorizedException
148
     */
149
    private function processTransferException(\Exception $e): void
150
    {
151
        switch ($e->getCode()) {
152
            case SymfonyResponse::HTTP_UNAUTHORIZED:
153
                throw new UnauthorizedException('Unauthorized', SymfonyResponse::HTTP_UNAUTHORIZED, $e);
154
            case SymfonyResponse::HTTP_NOT_FOUND:
155
                throw new NotFoundException('Resource not found', SymfonyResponse::HTTP_NOT_FOUND, $e);
156
            case SymfonyResponse::HTTP_FORBIDDEN:
157
                throw new ForbiddenException('Forbidden', SymfonyResponse::HTTP_FORBIDDEN, $e);
158
            case SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR:
159
            case SymfonyResponse::HTTP_NOT_IMPLEMENTED:
160
            case SymfonyResponse::HTTP_BAD_GATEWAY:
161
            case SymfonyResponse::HTTP_SERVICE_UNAVAILABLE:
162
            case SymfonyResponse::HTTP_GATEWAY_TIMEOUT:
163
                throw new ServerProblemException('Server error', SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR, $e);
164
        }
165
    }
166
    
167
    /**
168
     * @throws ForbiddenException
169
     * @throws NotFoundException
170
     * @throws ServerProblemException
171
     * @throws UnauthorizedException
172
     */
173
    private function checkResponse(ResponseInterface $response): void
174
    {
175
        $code = $response->getStatusCode();
176
        $reason = $response->getReasonPhrase();
177
178
        // @todo remove after fix
179
        // Temporary fix until @arts fixes this bug
180
        if ('{"error": "UserNotFound"}' === (string) $response->getBody()) {
181
            throw new NotFoundException('Not found', SymfonyResponse::HTTP_NOT_FOUND);
182
        } elseif ('{"message": "Forbidden", "code": 403, "error": "Forbidden"}' === (string) $response->getBody()) {
183
            throw new ForbiddenException('Forbidden', SymfonyResponse::HTTP_FORBIDDEN);
184
        }
185
186
        switch ($code) {
187
            case SymfonyResponse::HTTP_UNAUTHORIZED:
188
                throw new UnauthorizedException($reason, $code);
189
            case SymfonyResponse::HTTP_FORBIDDEN:
190
                throw new ForbiddenException($reason, $code);
191
            case SymfonyResponse::HTTP_NOT_FOUND:
192
                throw new NotFoundException($reason, $code);
193
            case SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR:
194
            case SymfonyResponse::HTTP_NOT_IMPLEMENTED:
195
            case SymfonyResponse::HTTP_BAD_GATEWAY:
196
            case SymfonyResponse::HTTP_SERVICE_UNAVAILABLE:
197
            case SymfonyResponse::HTTP_GATEWAY_TIMEOUT:
198
                throw new ServerProblemException($reason, $code);
199
        }
200
    }
201
}
202