Passed
Push — master ( c33233...da17a1 )
by Laurens
147:42
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 25
    public function __construct(ClientInterface $guzzleClient, string $clientId, string $clientSecret)
44
    {
45 25
        $this->guzzleClient = $guzzleClient;
46 25
        $this->clientId = $clientId;
47 25
        $this->clientSecret = $clientSecret;
48 25
    }
49
50 23
    public function setAccessToken(AccessToken $accessToken): void
51
    {
52 23
        $this->accessToken = $accessToken;
53 23
        $this->validateAccessToken();
54 22
    }
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 refreshAccessToken(?AccessToken $accessToken =  null): AccessToken
112
    {
113 1
        $accessToken = $accessToken ?? $this->accessToken;
114
        $options = [
115
            'form_params' => [
116 1
                'grant_type' => self::API_ACCESS_TOKEN_REFRESH_TOKEN_GRANT,
117 1
                'client_id' => $this->clientId,
118 1
                'client_secret' => $this->clientSecret,
119 1
                'refresh_token' => $accessToken->getRefreshToken()
120
            ],
121
        ];
122
123 1
        $this->setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REFRESH_TOKEN_URL, $options));
124
125 1
        return $this->accessToken;
126
    }
127
128 13
    public function get(string $url, ?array $queryParameters = null): ResponseInterface
129
    {
130 13
        $options =  array_merge(['headers' => $this->getAuthorizationHeader()], ['query' => $queryParameters]);
131
132
        try {
133 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...
134 1
        } catch (RequestException $exception) {
135 1
            GuzzleClientExceptionHandler::handleRequestException($exception);
136
        }
137
138 12
        return $response;
139
    }
140
141
    /**
142
     * @throws UnprocessableEntityException
143
     */
144 3
    public function post(string $url, IzettlePostable $postable): ResponseInterface
145
    {
146 3
        $headers = array_merge(
147 3
            $this->getAuthorizationHeader(),
148
            [
149 3
                'content-type' => 'application/json',
150
                'Accept' => 'application/json',
151
            ]
152
        );
153
154 3
        $options =  array_merge(['headers' => $headers], ['body' => $postable->getPostBodyData()]);
155
        try {
156 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...
157
        } catch (ClientException $exception) {
158
            throw new UnprocessableEntityException($exception->getResponse()->getBody()->getContents());
159
        }
160
    }
161
162
    /**
163
     * @throws UnprocessableEntityException
164
     */
165 2
    public function put(string $url, string $jsonData): void
166
    {
167 2
        $headers = array_merge(
168 2
            $this->getAuthorizationHeader(),
169
            [
170 2
                'content-type' => 'application/json',
171
                'Accept' => 'application/json',
172
            ]
173
        );
174
175 2
        $options =  array_merge(['headers' => $headers], ['body' => $jsonData]);
176
177
        try {
178 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...
179
        } catch (ClientException $exception) {
180
            throw new UnprocessableEntityException($exception->getResponse()->getBody()->getContents());
181
        }
182 2
    }
183
184
    /**
185
     * @throws UnprocessableEntityException
186
     */
187 1
    public function delete(string $url): void
188
    {
189
        try {
190 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...
191
        } catch (ClientException $exception) {
192
            throw new UnprocessableEntityException($exception->getResponse()->getBody()->getContents());
193
        }
194 1
    }
195
196 11
    public function getJson(ResponseInterface $response): string
197
    {
198 11
        return $response->getBody()->getContents();
199
    }
200
201 19
    private function getAuthorizationHeader(): array
202
    {
203 19
        $this->validateAccessToken();
204
205 19
        return ['Authorization' => sprintf('Bearer %s', $this->accessToken->getToken())];
206
    }
207
208 23
    private function validateAccessToken(): void
209
    {
210 23
        if ($this->accessToken->isExpired()) {
211 1
            throw new AccessTokenExpiredException(
212 1
                sprintf(
213 1
                    'Access Token was valid till \'%s\' it\'s now \'%s\'',
214 1
                    $this->accessToken->getExpires()->format('Y-m-d H:i:s.u'),
215 1
                    (new DateTime())->format('Y-m-d H:i:s.u')
216
                )
217
            );
218
        }
219 22
    }
220
221 3
    private function requestAccessToken($url, $options): AccessToken
222
    {
223 3
        $headers = ['headers' => ['Content-Type' => 'application/x-www-form-urlencoded']];
224 3
        $options = array_merge($headers, $options);
225
226 3
        $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...
227 2
        $data = json_decode($response->getBody()->getContents(), true);
228
229 2
        return new AccessToken(
230 2
            $data['access_token'],
231 2
            new DateTimeImmutable(sprintf('+%d second', $data['expires_in'])),
232 2
            $data['refresh_token']
233
        );
234
    }
235
}
236