HttpClientGateway::getAccessToken()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace TarfinLabs\Parasut\API;
4
5
use Illuminate\Http\Client\Response;
6
use Illuminate\Support\Carbon;
7
use Illuminate\Support\Facades\Http;
8
use RuntimeException;
9
use TarfinLabs\Parasut\Enums\ResourceNames;
10
use TarfinLabs\Parasut\Exceptions\BadRequestException;
11
use TarfinLabs\Parasut\Exceptions\ForbiddenException;
12
use TarfinLabs\Parasut\Exceptions\NotFoundException;
13
use TarfinLabs\Parasut\Exceptions\TooManyRequestsException;
14
use TarfinLabs\Parasut\Exceptions\UnauthorizedException;
15
use TarfinLabs\Parasut\Exceptions\UnprocessableEntityException;
16
17
class HttpClientGateway implements ClientGateway
18
{
19
    // TODO: Cache tokens
20
21
    private string $grantType;
22
    private string $clientId;
23
    private string $clientSecret;
24
    private string $username;
25
    private string $password;
26
    private string $redirectUri;
27
28
    private string $accessToken;
29
    private string $refreshToken;
30
    private Carbon $expiresAt;
31
32
    private string $baseEntpoint;
33
34 11
    public function __construct(
35
        string $grantType,
36
        string $clientId,
37
        string $clientSecret,
38
        string $username,
39
        string $password,
40
        string $redirectUri
41
    ) {
42 11
        $this->grantType = $grantType;
43 11
        $this->clientId = $clientId;
44 11
        $this->clientSecret = $clientSecret;
45 11
        $this->username = $username;
46 11
        $this->password = $password;
47 11
        $this->redirectUri = $redirectUri;
48
49 11
        $this->baseEntpoint = ResourceNames::buildEndpoint(
50 11
            config('parasut.api_url'),
51 11
            config('parasut.api_version'),
52 11
            config('parasut.company_id')
53
        );
54
55 11
        $this->authenticate();
56 11
    }
57
58 11
    public function getAccessToken(): string
59
    {
60 11
        return $this->accessToken;
61
    }
62
63 1
    public function getRefreshToken(): string
64
    {
65 1
        return $this->refreshToken;
66
    }
67
68 1
    public function getExpiresAt(): ?Carbon
69
    {
70 1
        return $this->expiresAt;
71
    }
72
73
    /**
74
     * Authenticate user and get API tokens from parasut.com.
75
     *
76
     * @return bool
77
     * @throws \TarfinLabs\Parasut\Exceptions\BadRequestException
78
     * @throws \TarfinLabs\Parasut\Exceptions\ForbiddenException
79
     * @throws \TarfinLabs\Parasut\Exceptions\NotFoundException
80
     * @throws \TarfinLabs\Parasut\Exceptions\TooManyRequestsException
81
     * @throws \TarfinLabs\Parasut\Exceptions\UnauthorizedException
82
     * @throws \TarfinLabs\Parasut\Exceptions\UnprocessableEntityException
83
     */
84 11
    public function authenticate(): bool
85
    {
86 11
        $response = Http::asForm()
87 11
                        ->post(
88
                            ResourceNames::buildEndpoint(
89 11
                                config('parasut.api_url'),
90 11
                                config('parasut.token_url')
91
                            ),
92
                            [
93 11
                                'grant_type'    => $this->grantType,
94 11
                                'client_id'     => $this->clientId,
95 11
                                'client_secret' => $this->clientSecret,
96 11
                                'username'      => $this->username,
97 11
                                'password'      => $this->password,
98 11
                                'redirect_uri'  => $this->redirectUri,
99
                            ]
100
                        );
101
102 11
        if ($response->successful()) {
103 11
            $this->accessToken = $response->json()['access_token'];
104 11
            $this->refreshToken = $response->json()['refresh_token'];
105 11
            $this->expiresAt = Carbon::now()->addSeconds($response->json()['expires_in']);
106
107 11
            return true;
108
        }
109
110
        $this->catchException($response);
111
    }
112
113 10
    protected function buildHttpQuery(
114
        $filters = null,
115
        $sorts = null,
116
        $includes = null,
117
        $page = null,
118
        $pageSize = null
119
    ): string {
120 10
        return http_build_query(
121
            array_filter([
122 10
                'filter'       => $filters,
123 10
                'sort'         => ! empty($sorts) ? implode(',', $sorts) : null,
124 10
                'include'      => ! empty($includes) ? implode(',', $includes) : null,
125 10
                'page[number]' => $page,
126 10
                'page[size]'   => $pageSize,
127
            ]));
128
    }
129
130 10
    public function send(
131
        string $method,
132
        array $endpoints,
133
        array $filters = null,
134
        array $sorts = null,
135
        array $includes = null,
136
        array $body = null,
137
        ?int $page,
138
        ?int $pageSize
139
    ): ?array {
140 10
        $url = ResourceNames::buildEndpoint($this->baseEntpoint, $endpoints);
141 10
        $queryString = $this->buildHttpQuery($filters, $sorts, $includes, $page, $pageSize);
142
143 10
        if (! empty($queryString)) {
144
            $url = implode('?', [$url, $queryString]);
145
        }
146
147 10
        $response = Http::withToken($this->getAccessToken())
148 10
                        ->send($method, $url, ['json' => $body]);
149
150 10
        if ($response->successful()) {
151 10
            return $response->json();
152
        }
153
154
        $this->catchException($response);
155
    }
156
157
    /**
158
     * Catches the status code and throws appropriate exception.
159
     *
160
     * @param  \Illuminate\Http\Client\Response  $response
161
     */
162
    protected function catchException(Response $response): void
163
    {
164
        switch ($response->status()) {
165
            case BadRequestException::$statusCode:
166
                $exceptionClass = BadRequestException::class;
167
                break;
168
            case ForbiddenException::$statusCode:
169
                $exceptionClass = ForbiddenException::class;
170
                break;
171
            case NotFoundException::$statusCode:
172
                $exceptionClass = NotFoundException::class;
173
                break;
174
            case TooManyRequestsException::$statusCode:
175
                $exceptionClass = TooManyRequestsException::class;
176
                break;
177
            case UnauthorizedException::$statusCode:
178
                $exceptionClass = UnauthorizedException::class;
179
                break;
180
            case UnprocessableEntityException::$statusCode:
181
                $exceptionClass = UnprocessableEntityException::class;
182
                break;
183
            default:
184
                $exceptionClass = RuntimeException::class;
185
                break;
186
        }
187
188
        throw new $exceptionClass($response);
189
    }
190
}
191