Test Setup Failed
Push — master ( 3336bf...41079a )
by Alexey
03:09
created

AbstractApi::processTransferException()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 17
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 7.756
c 0
b 0
f 0
cc 9
eloc 14
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;
8
use JMS\Serializer\Serializer;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\StreamInterface;
11
use Psr\Log\LoggerInterface;
12
use Skobkin\Bundle\PointToolsBundle\Exception\Api\ForbiddenException;
13
use Skobkin\Bundle\PointToolsBundle\Exception\Api\NetworkException;
14
use Skobkin\Bundle\PointToolsBundle\Exception\Api\NotFoundException;
15
use Skobkin\Bundle\PointToolsBundle\Exception\Api\ServerProblemException;
16
use Skobkin\Bundle\PointToolsBundle\Exception\Api\UnauthorizedException;
17
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
18
19
class AbstractApi
20
{
21
    /**
22
     * @var ClientInterface HTTP-client from Guzzle
23
     */
24
    protected $client;
25
26
    /**
27
     * @var Serializer
28
     */
29
    protected $serializer;
30
31
    /**
32
     * @var LoggerInterface
33
     */
34
    protected $logger;
35
36
    /**
37
     * @var string Authentication token for API
38
     */
39
    protected $authToken;
40
41
    /**
42
     * @var string CSRF-token for API
43
     */
44
    protected $csRfToken;
45
46
47
    public function __construct(ClientInterface $httpClient, Serializer $serializer, LoggerInterface $logger)
48
    {
49
        $this->client = $httpClient;
50
        $this->serializer = $serializer;
51
        $this->logger = $logger;
52
    }
53
54
    /**
55
     * Make GET request and return DTO objects
56
     *
57
     * @return array|object
58
     */
59
    public function getGetJsonData(string $path, array $parameters = [], string $type, DeserializationContext $context = null)
60
    {
61
        return $this->serializer->deserialize(
62
            $this->getGetResponseBody($path, $parameters),
63
            $type,
64
            'json',
65
            $context
66
        );
67
    }
68
69
    /**
70
     * Make POST request and return DTO objects
71
     *
72
     * @return array|object
73
     */
74
    public function getPostJsonData(string $path, array $parameters = [], string $type, DeserializationContext $context = null)
75
    {
76
        return $this->serializer->deserialize(
77
            $this->getPostResponseBody($path, $parameters),
78
            $type,
79
            'json',
80
            $context
81
        );
82
    }
83
84
    /**
85
     * Make GET request and return response body
86
     */
87
    public function getGetResponseBody($path, array $parameters = []): StreamInterface
88
    {
89
        return $this->sendGetRequest($path, $parameters)->getBody();
90
    }
91
92
    /**
93
     * Make POST request and return response body
94
     */
95
    public function getPostResponseBody(string $path, array $parameters = []): StreamInterface
96
    {
97
        return $this->sendPostRequest($path, $parameters)->getBody();
98
    }
99
100
    /**
101
     * @param string $path Request path
102
     * @param array $parameters Key => Value array of query parameters
103
     *
104
     * @return ResponseInterface
105
     *
106
     * @throws NetworkException
107
     */
108
    private function sendGetRequest(string $path, array $parameters = []): ResponseInterface
109
    {
110
        $this->logger->debug('Sending GET request', ['path' => $path, 'parameters' => $parameters]);
111
112
        return $this->sendRequest('GET', $path, ['query' => $parameters]);
113
    }
114
115
    /**
116
     * @param string $path Request path
117
     * @param array $parameters Key => Value array of request data
118
     *
119
     * @return ResponseInterface
120
     *
121
     * @throws NetworkException
122
     */
123
    private function sendPostRequest(string $path, array $parameters = []): ResponseInterface
124
    {
125
        $this->logger->debug('Sending POST request', ['path' => $path, 'parameters' => $parameters]);
126
127
        return $this->sendRequest('POST', $path, ['form_params' => $parameters]);
128
    }
129
130
    private function sendRequest(string $method, string $path, array $parameters): ResponseInterface
131
    {
132
        try {
133
            $response = $this->client->request($method, $path, ['query' => $parameters]);
134
135
            $this->checkResponse($response);
136
137
            return $response;
138
        } catch (TransferException $e) {
139
            $this->processTransferException($e);
140
            
141
            throw new NetworkException('Request error', $e->getCode(), $e);
142
        }
143
    }
144
145
    /**
146
     * @todo refactor with $this->checkResponse()
147
     *
148
     * @param \Exception $e
149
     *
150
     * @throws ForbiddenException
151
     * @throws NotFoundException
152
     * @throws ServerProblemException
153
     * @throws UnauthorizedException
154
     */
155
    private function processTransferException(\Exception $e): void
156
    {
157
        switch ($e->getCode()) {
158
            case SymfonyResponse::HTTP_UNAUTHORIZED:
159
                throw new UnauthorizedException('Unauthorized', SymfonyResponse::HTTP_UNAUTHORIZED, $e);
160
            case SymfonyResponse::HTTP_NOT_FOUND:
161
                throw new NotFoundException('Resource not found', SymfonyResponse::HTTP_NOT_FOUND, $e);
162
            case SymfonyResponse::HTTP_FORBIDDEN:
163
                throw new ForbiddenException('Forbidden', SymfonyResponse::HTTP_FORBIDDEN, $e);
164
            case SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR:
165
            case SymfonyResponse::HTTP_NOT_IMPLEMENTED:
166
            case SymfonyResponse::HTTP_BAD_GATEWAY:
167
            case SymfonyResponse::HTTP_SERVICE_UNAVAILABLE:
168
            case SymfonyResponse::HTTP_GATEWAY_TIMEOUT:
169
                throw new ServerProblemException('Server error', SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR, $e);
170
        }
171
    }
172
    
173
    /**
174
     * @throws ForbiddenException
175
     * @throws NotFoundException
176
     * @throws ServerProblemException
177
     * @throws UnauthorizedException
178
     */
179
    private function checkResponse(ResponseInterface $response): void
180
    {
181
        $code = $response->getStatusCode();
182
        $reason = $response->getReasonPhrase();
183
184
        // @todo remove after fix
185
        // Temporary fix until @arts fixes this bug
186
        if ('{"error": "UserNotFound"}' === (string) $response->getBody()) {
187
            throw new NotFoundException($reason, $code);
188
        }
189
190
        switch ($code) {
191
            case SymfonyResponse::HTTP_UNAUTHORIZED:
192
                throw new UnauthorizedException($reason, $code);
193
            case SymfonyResponse::HTTP_FORBIDDEN:
194
                throw new ForbiddenException($reason, $code);
195
            case SymfonyResponse::HTTP_NOT_FOUND:
196
                throw new NotFoundException($reason, $code);
197
            case SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR:
198
            case SymfonyResponse::HTTP_NOT_IMPLEMENTED:
199
            case SymfonyResponse::HTTP_BAD_GATEWAY:
200
            case SymfonyResponse::HTTP_SERVICE_UNAVAILABLE:
201
            case SymfonyResponse::HTTP_GATEWAY_TIMEOUT:
202
                throw new ServerProblemException($reason, $code);
203
        }
204
    }
205
}
206