Passed
Push — master ( c2faf8...afa411 )
by Al3x
11:51
created

RequestService::convertResponse()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 13
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 22
ccs 14
cts 14
cp 1
crap 4
rs 9.8333
1
<?php
2
declare(strict_types=1);
3
4
namespace InvoiceNinjaModule\Service;
5
6
use InvoiceNinjaModule\Exception\ApiAuthException;
7
use InvoiceNinjaModule\Exception\EmptyResponseException;
8
use InvoiceNinjaModule\Exception\HttpClientAuthException;
9
use InvoiceNinjaModule\Exception\HttpClientException;
10
use InvoiceNinjaModule\Options\Interfaces\RequestOptionsInterface;
11
use InvoiceNinjaModule\Options\Interfaces\ModuleOptionsInterface;
12
use InvoiceNinjaModule\Service\Interfaces\RequestServiceInterface;
13
use Laminas\Http\Client;
14
use Laminas\Http\Client\Adapter\Curl;
15
use Laminas\Http\Exception\InvalidArgumentException;
16
use Laminas\Http\Exception\RuntimeException;
17
use Laminas\Http\Request;
18
use Laminas\Http\Response;
19
use Laminas\Stdlib\Parameters;
20
use function array_key_exists;
21
use function is_array;
22
use function json_decode;
23
use function json_encode;
24
use function strlen;
25
use function strstr;
26
use function substr;
27
28
/**
29
 * Class RequestService
30
 */
31
final class RequestService implements RequestServiceInterface
32
{
33
    public const RETURN_KEY = 'data';
34
    private ModuleOptionsInterface $moduleOptions;
35
    private Client $httpClient;
36
37
    /**
38
     * RequestService constructor.
39
     *
40
     * @param ModuleOptionsInterface $moduleOptions
41
     * @param Client                 $client
42
     *
43
     * @throws InvalidArgumentException
44
     */
45 16
    public function __construct(ModuleOptionsInterface $moduleOptions, Client $client)
46
    {
47 16
        $this->moduleOptions = $moduleOptions;
48 16
        $this->httpClient    = $client;
49 16
        $this->initHttpClient();
50 16
    }
51
52
    /**
53
     * Sends the request to the server
54
     *
55
     * @param string                  $reqMethod
56
     * @param string                  $reqRoute
57
     * @param RequestOptionsInterface $requestOptions
58
     *
59
     * @return array
60
     * @throws ApiAuthException
61
     * @throws EmptyResponseException
62
     * @throws HttpClientException
63
     * @throws HttpClientAuthException
64
     */
65 14
    public function dispatchRequest(string $reqMethod, string $reqRoute, RequestOptionsInterface $requestOptions) :array
66
    {
67 14
        $request = new Request();
68 14
        $request->setAllowCustomMethods(false);
69
        try {
70 14
            $request->setMethod($reqMethod);
71 1
        } catch (InvalidArgumentException $e) {
72 1
            throw new HttpClientException($e->getMessage());
73
        }
74
75 13
        $request->setQuery(new Parameters($requestOptions->getQueryArray()));
76
77 13
        $postArray = $requestOptions->getPostArray();
78 13
        if (!empty($postArray)) {
79 1
            $request->setContent(json_encode($postArray));
80
        }
81
82
        try {
83 13
            $request->getHeaders()->addHeaders($this->getRequestHeaderArray());
84 13
            $request->setUri($this->moduleOptions->getHostUrl().$reqRoute);
85
        } catch (InvalidArgumentException $e) {
86
            throw new HttpClientException($e->getMessage());
87
        }
88
89
        try {
90 13
            $response = $this->httpClient->send($request);
91 1
        } catch (RuntimeException $e) {
92 1
            throw new HttpClientException($e->getMessage());
93
        }
94
95 12
        $this->checkResponseCode($response);
96
97 9
        return $this->convertResponse($response);
98
    }
99
100
    /**
101
     * @param Response $response
102
     *
103
     * @throws ApiAuthException
104
     * @throws HttpClientException
105
     * @throws HttpClientAuthException
106
     */
107 12
    private function checkResponseCode(Response $response) :void
108
    {
109 12
        switch ($response->getStatusCode()) {
110 12
            case Response::STATUS_CODE_200:
111 9
                break;
112 3
            case Response::STATUS_CODE_403:
113 1
                throw new ApiAuthException($response->getStatusCode() .' '.$response->getReasonPhrase());
114 2
            case Response::STATUS_CODE_401:
115 1
                throw new HttpClientAuthException($response->getStatusCode() .' '.$response->getReasonPhrase());
116
            default:
117 1
                throw new HttpClientException($response->getStatusCode() .' '.$response->getReasonPhrase());
118
        }
119 9
    }
120
121
    /**
122
     * @param Response $response
123
     *
124
     * @return array
125
     * @throws EmptyResponseException
126
     */
127 9
    private function convertResponse(Response $response) :array
128
    {
129 9
        $headers = $response->getHeaders();
130
        //check if it is a file
131 9
        $contentDisposition = $headers->get('Content-disposition');
132 9
        if ($contentDisposition !== false) {
133 2
            $needle = 'attachment; filename="';
134 2
            $subString = strstr($contentDisposition->getFieldValue(), $needle);
0 ignored issues
show
Bug introduced by
The method getFieldValue() does not exist on ArrayIterator. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

134
            $subString = strstr($contentDisposition->/** @scrutinizer ignore-call */ getFieldValue(), $needle);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
135
136 2
            if ($subString === false) {
137 1
                return [];
138
            }
139
140 1
            $fileName = substr($subString, strlen($needle), -1);
141 1
            return [$fileName => $response->getBody()];
142
        }
143
144 7
        $result = json_decode($response->getBody(), true);
145 7
        if (is_array($result)) {
146 6
            return $this->checkResponseKey($result);
147
        }
148 1
        throw new EmptyResponseException();
149
    }
150
151
    /**
152
     * @param array $result
153
     *
154
     * @return array
155
     * @throws EmptyResponseException
156
     */
157 6
    private function checkResponseKey(array $result) :array
158
    {
159 6
        if (!array_key_exists(self::RETURN_KEY, $result) || empty($result[self::RETURN_KEY])) {
160 2
            throw new EmptyResponseException();
161
        }
162 4
        return $result[self::RETURN_KEY];
163
    }
164
165
    /**
166
     * @return array
167
     */
168 13
    private function getRequestHeaderArray() :array
169
    {
170
        return [
171 13
            'Accept'                             => 'application/json',
172 13
            'Content-type'                       => 'application/json; charset=UTF-8',
173 13
            $this->moduleOptions->getTokenType() => $this->moduleOptions->getToken()
174
        ];
175
    }
176
177
    /**
178
     * @return void
179
     * @throws InvalidArgumentException
180
     */
181 16
    private function initHttpClient() :void
182
    {
183 16
        $options = [
184 16
            'timeout' => $this->moduleOptions->getTimeout()
185
        ];
186 16
        $this->httpClient->setOptions($options);
187 16
        $this->httpClient->setAdapter(Curl::class);
188
189 16
        $authOptions = $this->moduleOptions->getAuthOptions();
190
191 16
        if ($authOptions->isAuthorization()) {
192 1
            $this->httpClient->setAuth(
193 1
                $authOptions->getUsername(),
194 1
                $authOptions->getPassword(),
195 1
                $authOptions->getAuthType()
196
            );
197
        }
198 16
    }
199
}
200