SDK::use()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Suitcase\Builder;
6
7
use GuzzleHttp\Client;
8
use GuzzleHttp\Psr7\Response;
9
use Suitcase\Builder\ParameterBag;
10
use GuzzleHttp\Exception\GuzzleException;
11
use Tightenco\Collect\Support\Collection;
12
use Suitcase\Builder\Exceptions\MethodNotAllowed;
13
use Suitcase\Builder\Exceptions\ResourceException;
14
use Suitcase\Builder\Exceptions\UnsupportedScheme;
15
use Suitcase\Builder\Exceptions\ResourceNotRegistered;
16
17
final class SDK
18
{
19
    protected array $resource;
20
21
    protected string $scheme;
22
23
    protected string $host;
24
25
    protected string $path;
26
27
    protected string $appends = '';
28
29
    protected array $url;
30
31
    protected string $authHeader = '';
32
33
    protected Client $client;
34
35
    protected ParameterBag $query;
36
37
    protected Collection $resources;
38
39
    protected array $allowedSchemes = [
40
        'http',
41
        'https'
42
    ];
43
44 52
    private function __construct(string $url)
45
    {
46 52
        $parts = array_merge(parse_url($url));
47
48 52
        $this->scheme = isset($parts['scheme']) ? $this->allowedScheme($parts['scheme']) : '';
49 50
        $this->host = $parts['host'] ?? '';
50 50
        $this->path = $parts['path'] ?? '/';
51 50
        $this->client = new Client();
52 50
        $this->query = new ParameterBag();
53 50
        $this->resources = new Collection();
54 50
    }
55
56 52
    public static function make(string $url): self
57
    {
58 52
        return new self($url);
59
    }
60
61 34
    public function add(string $name, array $options = []): void
62
    {
63
        $resource = [
64 34
            'name' => $name,
65 34
            'endpoint' => array_key_exists('endpoint', $options) ? $options['endpoint'] : $name,
66 34
            'allows' => array_key_exists('allows', $options) ? $options['allows'] : [
67
                'get', 'find', 'create', 'update', 'delete'
68
            ],
69
        ];
70
71 34
        $this->resources->push($resource);
72 34
    }
73
74 20
    public function getScheme(): string
75
    {
76 20
        return $this->scheme;
77
    }
78
79 20
    public function getHost(): string
80
    {
81 20
        return $this->host;
82
    }
83
84 20
    public function getPath(): string
85
    {
86 20
        return $this->path;
87
    }
88
89 12
    public function getResources(): Collection
90
    {
91 12
        return $this->resources;
92
    }
93
94 2
    public function getQuery(): ParameterBag
95
    {
96 2
        return $this->query;
97
    }
98
99 2
    public function getClient(): Client
100
    {
101 2
        return $this->client;
102
    }
103
104 26
    public function use(string $resource): self
105
    {
106 26
        if (! $this->resources->pluck('name')->contains($resource)) {
107 2
            throw new ResourceNotRegistered("No resource registered for: {$resource}");
108
        }
109
110 24
        $this->resource = $this->resources->where('name', $resource)->first();
111
112 24
        return $this;
113
    }
114
115 2
    public function getResource():? array
116
    {
117 2
        return $this->resource;
118
    }
119
120 8
    public function get(string $method = 'GET')
121
    {
122 8
        if (! $this->checkAbility('get')) {
123
            throw new MethodNotAllowed("Method get is not available on this resource");
124
        }
125
126 8
        return $this->call($method, $this->resource['endpoint']);
127
    }
128
129 6
    public function find($identifier, string $method = 'GET')
130
    {
131 6
        if (! $this->checkAbility('find')) {
132 2
            throw new MethodNotAllowed("Method find is not available on this resource");
133
        }
134
135 4
        return $this->call($method, $this->resource['endpoint'] . '/' . (string) $identifier);
136
    }
137
138 2
    public function create(array $data)
139
    {
140 2
        if (! $this->checkAbility('create')) {
141
            throw new MethodNotAllowed("Method create is not available on this resource");
142
        }
143
144 2
        return $this->call('POST', $this->resource['endpoint'], $data);
145
    }
146
147 2
    public function update($identifier, array $data, string $method = 'PUT')
148
    {
149 2
        if (! $this->checkAbility('update')) {
150
            throw new MethodNotAllowed("Method update is not available on this resource");
151
        }
152
153 2
        return $this->call($method, $this->resource['endpoint'] . '/' . (string) $identifier, $data);
154
    }
155
156 2
    public function delete($identifier, string $method = 'DELETE')
157
    {
158 2
        if (! $this->checkAbility('delete')) {
159
            throw new MethodNotAllowed("Method delete is not available on this resource");
160
        }
161
162 2
        return $this->call($method, $this->resource['endpoint'] . '/' . (string) $identifier);
163
    }
164
165 2
    public function append(...$appends): self
166
    {
167 2
        $this->appends = implode('/', $appends);
168
169 2
        return $this;
170
    }
171
172
    public function withAuthHeaders(string $credentials, string $type = 'Bearer'): self
173
    {
174
        $this->authHeader = "{$type} {$credentials}";
175
176
        return $this;
177
    }
178
179
    /**
180
     * @codeCoverageIgnore
181
     */
182 20
    protected function checkAbility(string $method)
183
    {
184 20
        return collect($this->resource['allows'])->contains($method);
185
    }
186
187
    /**
188
     * @codeCoverageIgnore
189
     */
190 18
    protected function call(string $method, string $endpoint, array $data = []): \Psr\Http\Message\ResponseInterface
191
    {
192 18
        $uri = $this->buildUri($endpoint);
193
194 18
        if ($this->authHeader !== '') {
195
            $data['headers']['Authorization'] = "{$this->authHeader}";
196
        }
197
198
        try {
199 18
            $response = $this->client->request(
200 18
                $method,
201
                $uri,
202
                $data
203
            );
204 2
        } catch (GuzzleException $e) {
205 2
            throw new ResourceException($e->getMessage());
206
        }
207
208 16
        return $response;
209
    }
210
211
    /**
212
     * @codeCoverageIgnore
213
     */
214 18
    protected function buildUri(string $endpoint): string
215
    {
216 18
        $uri = '';
217
218 18
        if ($this->getScheme() !== '') {
219 18
            $uri .= $this->getScheme() . '://';
220
        }
221
222 18
        if ($this->getHost() !== '') {
223 18
            $uri .= $this->getHost();
224
        }
225
226 18
        $uri .= rtrim($this->getPath(), '/');
227
228 18
        $uri .= '/' . rtrim($endpoint, '/');
229
230 18
        $uri .= '/' . rtrim($this->appends, '/');
231
232 18
        return $uri;
233
    }
234
235
    /**
236
     * @codeCoverageIgnore
237
     */
238 52
    protected function allowedScheme(string $scheme): string
239
    {
240 52
        $scheme = strtolower($scheme);
241
242 52
        if (! in_array($scheme, $this->allowedSchemes)) {
243 2
            throw new UnsupportedScheme(
244 2
                "The scheme `{$scheme}` isn't valid. It should be either `http` or `https`."
245
            );
246
        }
247
248 50
        return $scheme;
249
    }
250
}
251