Test Failed
Branch feature/v1_stable_fixes (e805e7)
by Diego
04:22
created

Client::__call()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 8
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Blackmine\Client;
6
7
use Blackmine\Client\Generator\CacheKeyGenerator;
8
use Blackmine\Repository\CacheableRepository;
9
use Blackmine\Repository\CustomFields;
10
use Blackmine\Repository\Enumerations;
11
use Blackmine\Repository\Issues\Relations;
12
use Blackmine\Repository\Issues\Statuses;
13
use Blackmine\Repository\Projects\IssueCategories;
14
use Blackmine\Repository\Projects\TimeEntries;
15
use Blackmine\Repository\Projects\Trackers;
16
use Blackmine\Repository\Projects\Versions;
17
use Blackmine\Repository\Projects\WikiPages;
18
use Blackmine\Repository\Queries;
19
use Blackmine\Repository\RepositoryInterface;
20
use Blackmine\Repository\Uploads;
21
use Blackmine\Repository\Users\Groups;
22
use Blackmine\Repository\Users\Roles;
23
use Blackmine\Tool\Inflect;
24
use Error;
25
use JsonException;
26
use Blackmine\Client\Response\ApiResponse;
27
use Requests;
28
use Blackmine\Repository\AbstractRepository;
29
use Blackmine\Repository\Issues\Issues;
30
use Blackmine\Repository\Projects\Projects;
31
use Blackmine\Repository\Users\Users;
32
use Symfony\Contracts\Cache\CacheInterface;
33
34
/**
35
 * @method AbstractRepository Issues();
36
 * @method AbstractRepository Users();
37
 * @method AbstractRepository Projects();
38
 * @method AbstractRepository Memberships();
39
 * @method AbstractRepository Trackers();
40
 * @method AbstractRepository IssueStatuses();
41
 * @method AbstractRepository IssueCategories();
42
 * @method AbstractRepository Relations();
43
 * @method AbstractRepository Groups();
44
 * @method AbstractRepository Versions();
45
 * @method AbstractRepository TimeEntries();
46
 * @method AbstractRepository Roles();
47
 * @method AbstractRepository Enumerations();
48
 * @method AbstractRepository Queries();
49
 * @method AbstractRepository WikiPages();
50
 * @method AbstractRepository Files();
51
 * @method AbstractRepository Attachments();
52
 * @method AbstractRepository CustomFields();
53
 * @method AbstractRepository News();
54
*/
55
class Client implements ClientInterface
56
{
57
    /**
58
     * @param ClientOptions $options
59
     * @param CacheInterface|null $cache
60
     */
61
    public function __construct(
62
        protected ClientOptions $options,
63
        protected ?CacheInterface $cache = null
64
    ) {
65
    }
66
67
    /**
68
     * @param string $endpoint
69
     * @return RepositoryInterface|null
70
     */
71
    public function getRepository(string $endpoint): ?RepositoryInterface
72
    {
73
        $repository = $this->getRepositoryForEndpoint($endpoint);
74
        if ($repository && $this->cache) {
75
            return new CacheableRepository(
76
                $repository,
77
                $this->cache,
78
                new CacheKeyGenerator($this->options->get(ClientOptions::CLIENT_OPTION_API_KEY))
79
            );
80
        }
81
82
        return $repository;
83
    }
84
85
    /**
86
     * @param string $method
87
     * @param array $args
88
     * @return AbstractRepository|null
89
     * @ignore
90
     */
91
    public function __call(string $method, array $args): ?AbstractRepository
92
    {
93
        $repository = $this->getRepositoryForEndpoint(Inflect::snakeize($method));
94
        if ($repository) {
95
            return $repository;
96
        }
97
98
        throw new Error("Undefined repository for api: " . Inflect::snakeize($method));
99
    }
100
101
    private function getRepositoryForEndpoint(string $endpoint): ?AbstractRepository
102
    {
103
        return match ($endpoint) {
104
            Issues::API_ROOT => new Issues($this),
105
            Users::API_ROOT => new Users($this),
106
            Projects::API_ROOT => new Projects($this),
107
            IssueCategories::API_ROOT => new IssueCategories($this),
108
            TimeEntries::API_ROOT => new TimeEntries($this),
109
            Trackers::API_ROOT => new Trackers($this),
110
            Statuses::API_ROOT => new Statuses($this),
111
            Relations::API_ROOT => new Relations($this),
112
            Groups::API_ROOT => new Groups($this),
113
            Versions::API_ROOT => new Versions($this),
114
            Roles::API_ROOT => new Roles($this),
115
            CustomFields::API_ROOT => new CustomFields($this),
116
            Uploads::API_ROOT => new Uploads($this),
117
            Enumerations::API_ROOT => new Enumerations($this),
118
            Queries::API_ROOT => new Queries($this),
119
            WikiPages::API_ROOT => new WikiPages($this),
120
            default => null,
121
        };
122
    }
123
124
    /**
125
     * @param string $endpoint
126
     * @param string $body
127
     * @param array $headers
128
     * @return ApiResponse
129
     * @throws JsonException
130
     */
131
    public function post(string $endpoint, string $body = '', array $headers = []): ApiResponse
132
    {
133
        $response = Requests::post($this->getEndpointUrl($endpoint), $this->getRequestHeaders($headers), $body);
134
        return ApiResponse::fromRequestsResponse($response);
135
    }
136
137
    /**
138
     * @param string $endpoint
139
     * @param array $headers
140
     * @return ApiResponse
141
     * @throws JsonException
142
     */
143
    public function get(string $endpoint, array $headers = []): ApiResponse
144
    {
145
        $response = Requests::get($this->getEndpointUrl($endpoint), $this->getRequestHeaders($headers));
146
        return ApiResponse::fromRequestsResponse($response);
147
    }
148
149
    /**
150
     * @param string $endpoint
151
     * @param string|null $body
152
     * @param array $headers
153
     * @return ApiResponse
154
     * @throws JsonException
155
     */
156
    public function put(string $endpoint, ?string $body = null, array $headers = []): ApiResponse
157
    {
158
        $response = Requests::put($this->getEndpointUrl($endpoint), $this->getRequestHeaders($headers), $body);
159
        return ApiResponse::fromRequestsResponse($response);
160
    }
161
162
    /**
163
     * @param string $endpoint
164
     * @param array $headers
165
     * @return ApiResponse
166
     * @throws JsonException
167
     */
168
    public function delete(string $endpoint, array $headers = []): ApiResponse
169
    {
170
        $response = Requests::delete($this->getEndpointUrl($endpoint), $this->getRequestHeaders($headers));
171
        return ApiResponse::fromRequestsResponse($response);
172
    }
173
174
    /**
175
     * @return string
176
     */
177
    public function getFormat(): string
178
    {
179
        return $this->options->get(ClientOptions::CLIENT_OPTION_FORMAT);
180
    }
181
182
    private function getRequestHeaders(array $headers): array
183
    {
184
        if (!empty($headers)) {
185
            return array_merge($this->options->get(ClientOptions::CLIENT_OPTION_REQUEST_HEADERS), $headers);
186
        }
187
188
        return $this->options->get(ClientOptions::CLIENT_OPTION_REQUEST_HEADERS);
189
    }
190
191
    private function getEndpointUrl(string $endpoint): string
192
    {
193
        return $this->options->get(ClientOptions::CLIENT_OPTION_BASE_URL) . "/" . $endpoint;
194
    }
195
}
196