Test Failed
Push — master ( 257d98...3364ef )
by Yunus Emre
06:12
created

HttpClientGateway   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 172
Duplicated Lines 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
wmc 19
eloc 79
c 8
b 0
f 0
dl 0
loc 172
rs 10

8 Methods

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