Completed
Push — master ( 59c270...a4b6fc )
by Laurens
02:53
created

getAccessTokenFromAuthorizedCode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 0
cts 10
cp 0
rs 9.6
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LauLamanApps\IzettleApi;
6
7
use DateTime;
8
use DateTimeImmutable;
9
use GuzzleHttp\ClientInterface;
10
use GuzzleHttp\Exception\ClientException;
11
use GuzzleHttp\Exception\RequestException;
12
use LauLamanApps\IzettleApi\API\Universal\IzettlePostable;
13
use LauLamanApps\IzettleApi\Client\AccessToken;
14
use LauLamanApps\IzettleApi\Client\ApiScope;
15
use LauLamanApps\IzettleApi\Client\Exception\AccessTokenExpiredException;
16
use LauLamanApps\IzettleApi\Client\Exception\GuzzleClientExceptionHandler;
17
use LauLamanApps\IzettleApi\Exception\NotFoundException;
18
use Psr\Http\Message\ResponseInterface;
19
20
class GuzzleIzettleClient implements IzettleClientInterface
21
{
22
    /**
23
     * @var ClientInterface
24
     */
25
    private $guzzleClient;
26
27
    /**
28
     * @var string
29
     */
30
    private $clientId;
31
32
    /**
33
     * @var string
34
     */
35
    private $clientSecret;
36
37
    /**
38
     * @var AccessToken
39
     */
40
    private $accessToken;
41
42 25
    public function __construct(ClientInterface $guzzleClient, string $clientId, string $clientSecret)
43
    {
44 25
        $this->guzzleClient = $guzzleClient;
45 25
        $this->clientId = $clientId;
46 25
        $this->clientSecret = $clientSecret;
47 25
    }
48
49 23
    public function setAccessToken(AccessToken $accessToken): void
50
    {
51 23
        $this->accessToken = $accessToken;
52 23
        $this->validateAccessToken();
53 22
    }
54
55 1
    public function authoriseUserLogin(string $redirectUrl, ApiScope $apiScope): string
56
    {
57 1
        $url = self::API_AUTHORIZE_USER_LOGIN_URL;
58 1
        $url .= '?response_type=code';
59 1
        $url .= '&redirect_uri=' . $redirectUrl;
60 1
        $url .= '&client_id=' . $this->clientId;
61 1
        $url .= '&scope=' . $apiScope->getUrlParameters();
62 1
        $url .= '&state=oauth2';
63
64 1
        return $url;
65
    }
66
67
    
68
	public function getAccessTokenFromAuthorizedCode(string $redirectUrl, string $code ): AccessToken
69
	{
70
		$options = [
71
		   'form_params' => [
72
			  'grant_type' => self::API_ACCESS_TOKEN_CODE_GRANT,
73
			  'client_id' => $this->clientId,
74
			  'client_secret' => $this->clientSecret,
75
			  'redirect_uri' => $redirectUrl,
76
			  'code' => $code
77
		   ],
78
		];
79
80
		try {
81
			$this->setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REQUEST_URL, $options));
82
		} catch (ClientException $exception) {
83
			GuzzleClientExceptionHandler::handleClientException($exception);
84
		}
85
86
		return $this->accessToken;
87
	}
88
    
89 2
    public function getAccessTokenFromUserLogin(string $username, string $password): AccessToken
90
    {
91
        $options = [
92
            'form_params' => [
93 2
                'grant_type' => self::API_ACCESS_TOKEN_PASSWORD_GRANT,
94 2
                'client_id' => $this->clientId,
95 2
                'client_secret' => $this->clientSecret,
96 2
                'username' => $username,
97 2
                'password' => $password
98
            ],
99
        ];
100
101
        try {
102 2
            $this->setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REQUEST_URL, $options));
103 1
        } catch (ClientException $exception) {
104 1
            GuzzleClientExceptionHandler::handleClientException($exception);
105
        }
106
107 1
        return $this->accessToken;
108
    }
109
110 1
    public function refreshAccessToken(?AccessToken $accessToken =  null): AccessToken
111
    {
112 1
        $accessToken = $accessToken ?? $this->accessToken;
113
        $options = [
114
            'form_params' => [
115 1
                'grant_type' => self::API_ACCESS_TOKEN_REFRESH_TOKEN_GRANT,
116 1
                'client_id' => $this->clientId,
117 1
                'client_secret' => $this->clientSecret,
118 1
                'refresh_token' => $accessToken->getRefreshToken()
119
            ],
120
        ];
121
122 1
        $this->setAccessToken($this->requestAccessToken(self::API_ACCESS_TOKEN_REFRESH_TOKEN_URL, $options));
123
124 1
        return $this->accessToken;
125
    }
126
127 13
    public function get(string $url, ?array $queryParameters = null): ResponseInterface
128
    {
129 13
        $options =  array_merge(['headers' => $this->getAuthorizationHeader()], ['query' => $queryParameters]);
130
131
        try {
132 13
            $response = $this->guzzleClient->get($url, $options);
133 1
        } catch (RequestException $exception) {
134 1
            GuzzleClientExceptionHandler::handleRequestException($exception);
135
        }
136
137 12
        return $response;
138
    }
139
140 3
    public function post(string $url, IzettlePostable $postable): ResponseInterface
141
    {
142 3
        $headers = array_merge(
143 3
            $this->getAuthorizationHeader(),
144
            [
145 3
                'content-type' => 'application/json',
146
                'Accept' => 'application/json',
147
            ]
148
        );
149
150 3
        $options =  array_merge(['headers' => $headers], ['body' => $postable->getPostBodyData()]);
151
152 3
        return $this->guzzleClient->post($url, $options);
153
    }
154
155 2
    public function put(string $url, string $jsonData): void
156
    {
157 2
        $headers = array_merge(
158 2
            $this->getAuthorizationHeader(),
159
            [
160 2
                'content-type' => 'application/json',
161
                'Accept' => 'application/json',
162
            ]
163
        );
164
165 2
        $options =  array_merge(['headers' => $headers], ['body' => $jsonData]);
166
167 2
        $this->guzzleClient->put($url, $options);
168 2
    }
169
170 1
    public function delete(string $url): void
171
    {
172 1
        $this->guzzleClient->delete($url, ['headers' => $this->getAuthorizationHeader()]);
173 1
    }
174
175 11
    public function getJson(ResponseInterface $response): string
176
    {
177 11
        return $response->getBody()->getContents();
178
    }
179
180 19
    private function getAuthorizationHeader(): array
181
    {
182 19
        $this->validateAccessToken();
183
184 19
        return ['Authorization' => sprintf('Bearer %s', $this->accessToken->getToken())];
185
    }
186
187 23
    private function validateAccessToken(): void
188
    {
189 23
        if ($this->accessToken->isExpired()) {
190 1
            throw new AccessTokenExpiredException(
191 1
                sprintf(
192 1
                    'Access Token was valid till \'%s\' it\'s now \'%s\'',
193 1
                    $this->accessToken->getExpires()->format('Y-m-d H:i:s.u'),
194 1
                    (new DateTime())->format('Y-m-d H:i:s.u')
195
                )
196
            );
197
        }
198 22
    }
199
200 3
    private function requestAccessToken($url, $options): AccessToken
201
    {
202 3
        $headers = ['headers' => ['Content-Type' => 'application/x-www-form-urlencoded']];
203 3
        $options = array_merge($headers, $options);
204
205 3
        $response = $this->guzzleClient->post($url, $options);
206 2
        $data = json_decode($response->getBody()->getContents(), true);
207
208 2
        return new AccessToken(
209 2
            $data['access_token'],
210 2
            new DateTimeImmutable(sprintf('+%d second', $data['expires_in'])),
211 2
            $data['refresh_token']
212
        );
213
    }
214
}
215