Passed
Pull Request — master (#45)
by
unknown
02:06
created

GuzzleIzettleClient::put()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2.0438

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 7
cts 9
cp 0.7778
rs 9.6666
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2.0438
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LauLamanApps\IzettleApi;
6
7
use DateTime;
8
use DateTimeImmutable;
9
use GuzzleHttp\Client;
10
use GuzzleHttp\ClientInterface;
11
use GuzzleHttp\Exception\ClientException;
12
use GuzzleHttp\Exception\RequestException;
13
use LauLamanApps\IzettleApi\API\Universal\IzettlePostable;
14
use LauLamanApps\IzettleApi\Client\AccessToken;
15
use LauLamanApps\IzettleApi\Client\ApiScope;
16
use LauLamanApps\IzettleApi\Client\Exception\AccessTokenExpiredException;
17
use LauLamanApps\IzettleApi\Client\Exception\GuzzleClientExceptionHandler;
18
use LauLamanApps\IzettleApi\Exception\UnprocessableEntityException;
19
use Psr\Http\Message\ResponseInterface;
20
21
class GuzzleIzettleClient implements IzettleClientInterface
22
{
23
    /**
24
     * @var ClientInterface|Client
25
     */
26
    private $guzzleClient;
27
28
    /**
29
     * @var string
30
     */
31
    private $clientId;
32
33
    /**
34
     * @var string
35
     */
36
    private $clientSecret;
37
38
    /**
39
     * @var AccessToken
40
     */
41
    private $accessToken;
42
43 26
    public function __construct(ClientInterface $guzzleClient, string $clientId, string $clientSecret)
44
    {
45 26
        $this->guzzleClient = $guzzleClient;
46 26
        $this->clientId = $clientId;
47 26
        $this->clientSecret = $clientSecret;
48 26
    }
49
50 24
    public function setAccessToken(AccessToken $accessToken): void
51
    {
52 24
        $this->accessToken = $accessToken;
53 24
        $this->validateAccessToken();
54 23
    }
55
56 1
    public function authoriseUserLogin(string $redirectUrl, ApiScope $apiScope): string
57
    {
58 1
        $url = self::API_AUTHORIZE_USER_LOGIN_URL;
59 1
        $url .= '?response_type=code';
60 1
        $url .= '&redirect_uri=' . $redirectUrl;
61 1
        $url .= '&client_id=' . $this->clientId;
62 1
        $url .= '&scope=' . $apiScope->getUrlParameters();
63 1
        $url .= '&state=oauth2';
64
65 1
        return $url;
66
    }
67
68
    
69
    public function getAccessTokenFromAuthorizedCode(string $redirectUrl, string $code): AccessToken
70
    {
71
        $options = [
72
           'form_params' => [
73
              'grant_type' => self::API_ACCESS_TOKEN_CODE_GRANT,
74
              'client_id' => $this->clientId,
75
              'client_secret' => $this->clientSecret,
76
              'redirect_uri' => $redirectUrl,
77
              'code' => $code
78
           ],
79
        ];
80
81
        try {
82
            $this->setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REQUEST_URL, $options));
83
        } catch (ClientException $exception) {
84
            GuzzleClientExceptionHandler::handleClientException($exception);
85
        }
86
87
        return $this->accessToken;
88
    }
89
    
90 2
    public function getAccessTokenFromUserLogin(string $username, string $password): AccessToken
91
    {
92
        $options = [
93
            'form_params' => [
94 2
                'grant_type' => self::API_ACCESS_TOKEN_PASSWORD_GRANT,
95 2
                'client_id' => $this->clientId,
96 2
                'client_secret' => $this->clientSecret,
97 2
                'username' => $username,
98 2
                'password' => $password
99
            ],
100
        ];
101
102
        try {
103 2
            $this->setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REQUEST_URL, $options));
104 1
        } catch (ClientException $exception) {
105 1
            GuzzleClientExceptionHandler::handleClientException($exception);
106
        }
107
108 1
        return $this->accessToken;
109
    }
110
111 1
    public function getAccessTokenFromApiTokenAssertion(string $assertion): AccessToken
112
    {
113
        $options = [
114
            'form_params' => [
115 1
                'grant_type' => self::API_ACCESS_ASSERTION_GRANT,
116 1
                'client_id' => $this->clientId,
117 1
                'assertion' => $assertion
118
            ],
119
        ];
120
121
        try {
122 1
            $this->setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REQUEST_URL, $options));
123
        } catch (ClientException $exception) {
124
            GuzzleClientExceptionHandler::handleClientException($exception);
125
        }
126
127 1
        return $this->accessToken;
128
    }
129
130 1
    public function refreshAccessToken(?AccessToken $accessToken =  null): AccessToken
131
    {
132 1
        $accessToken = $accessToken ?? $this->accessToken;
133
        $options = [
134
            'form_params' => [
135 1
                'grant_type' => self::API_ACCESS_TOKEN_REFRESH_TOKEN_GRANT,
136 1
                'client_id' => $this->clientId,
137 1
                'client_secret' => $this->clientSecret,
138 1
                'refresh_token' => $accessToken->getRefreshToken()
139
            ],
140
        ];
141
142 1
        $this->setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REFRESH_TOKEN_URL, $options));
143
144 1
        return $this->accessToken;
145
    }
146
147 13
    public function get(string $url, ?array $queryParameters = null): ResponseInterface
148
    {
149 13
        $options =  array_merge(['headers' => $this->getAuthorizationHeader()], ['query' => $queryParameters]);
150
151
        try {
152 13
            $response = $this->guzzleClient->get($url, $options);
0 ignored issues
show
Bug introduced by
The method get does only exist in GuzzleHttp\Client, but not in GuzzleHttp\ClientInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
153 1
        } catch (RequestException $exception) {
154 1
            GuzzleClientExceptionHandler::handleRequestException($exception);
155
        }
156
157 12
        return $response;
158
    }
159
160
    /**
161
     * @throws UnprocessableEntityException
162
     */
163 3
    public function post(string $url, IzettlePostable $postable): ResponseInterface
164
    {
165 3
        $headers = array_merge(
166 3
            $this->getAuthorizationHeader(),
167
            [
168 3
                'content-type' => 'application/json',
169
                'Accept' => 'application/json',
170
            ]
171
        );
172
173 3
        $options =  array_merge(['headers' => $headers], ['body' => $postable->getPostBodyData()]);
174
        try {
175 3
            return $this->guzzleClient->post($url, $options);
0 ignored issues
show
Bug introduced by
The method post does only exist in GuzzleHttp\Client, but not in GuzzleHttp\ClientInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
176
        } catch (ClientException $exception) {
177
            throw new UnprocessableEntityException($exception->getResponse()->getBody()->getContents());
178
        }
179
    }
180
181
    /**
182
     * @throws UnprocessableEntityException
183
     */
184 2
    public function put(string $url, string $jsonData): void
185
    {
186 2
        $headers = array_merge(
187 2
            $this->getAuthorizationHeader(),
188
            [
189 2
                'content-type' => 'application/json',
190
                'Accept' => 'application/json',
191
            ]
192
        );
193
194 2
        $options =  array_merge(['headers' => $headers], ['body' => $jsonData]);
195
196
        try {
197 2
            $this->guzzleClient->put($url, $options);
0 ignored issues
show
Bug introduced by
The method put does only exist in GuzzleHttp\Client, but not in GuzzleHttp\ClientInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
198
        } catch (ClientException $exception) {
199
            throw new UnprocessableEntityException($exception->getResponse()->getBody()->getContents());
200
        }
201 2
    }
202
203
    /**
204
     * @throws UnprocessableEntityException
205
     */
206 1
    public function delete(string $url): void
207
    {
208
        try {
209 1
            $this->guzzleClient->delete($url, ['headers' => $this->getAuthorizationHeader()]);
0 ignored issues
show
Bug introduced by
The method delete does only exist in GuzzleHttp\Client, but not in GuzzleHttp\ClientInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
210
        } catch (ClientException $exception) {
211
            throw new UnprocessableEntityException($exception->getResponse()->getBody()->getContents());
212
        }
213 1
    }
214
215 11
    public function getJson(ResponseInterface $response): string
216
    {
217 11
        return $response->getBody()->getContents();
218
    }
219
220 19
    private function getAuthorizationHeader(): array
221
    {
222 19
        $this->validateAccessToken();
223
224 19
        return ['Authorization' => sprintf('Bearer %s', $this->accessToken->getToken())];
225
    }
226
227 24
    private function validateAccessToken(): void
228
    {
229 24
        if ($this->accessToken->isExpired()) {
230 1
            throw new AccessTokenExpiredException(
231 1
                sprintf(
232 1
                    'Access Token was valid till \'%s\' it\'s now \'%s\'',
233 1
                    $this->accessToken->getExpires()->format('Y-m-d H:i:s.u'),
234 1
                    (new DateTime())->format('Y-m-d H:i:s.u')
235
                )
236
            );
237
        }
238 23
    }
239
240 4
    private function requestAccessToken($url, $options): AccessToken
241
    {
242 4
        $headers = ['headers' => ['Content-Type' => 'application/x-www-form-urlencoded']];
243 4
        $options = array_merge($headers, $options);
244
245 4
        $response = $this->guzzleClient->post($url, $options);
0 ignored issues
show
Bug introduced by
The method post does only exist in GuzzleHttp\Client, but not in GuzzleHttp\ClientInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
246 3
        $data = json_decode($response->getBody()->getContents(), true);
247
248 3
        return new AccessToken(
249 3
            $data['access_token'],
250 3
            new DateTimeImmutable(sprintf('+%d second', $data['expires_in'])),
251 3
            $data['refresh_token']
252
        );
253
    }
254
}
255