LinodeClient::put()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
c 0
b 0
f 0
rs 10
ccs 4
cts 4
cp 1
cc 3
nc 2
nop 3
crap 3
1
<?php
2
3
// ---------------------------------------------------------------------
4
//
5
//  Copyright (C) 2018-2024 Artem Rodygin
6
//
7
//  You should have received a copy of the MIT License along with
8
//  this file. If not, see <https://opensource.org/licenses/MIT>.
9
//
10
// ---------------------------------------------------------------------
11
12
namespace Linode;
13
14
use GuzzleHttp\Client;
15
use GuzzleHttp\ClientInterface;
16
use GuzzleHttp\Exception\ClientException;
17
use GuzzleHttp\Exception\GuzzleException;
18
use GuzzleHttp\Psr7\Response;
19
use Linode\Exception\LinodeException;
20
use Psr\Http\Message\ResponseInterface;
21
22
/**
23
 * Linode API client.
24
 *
25
 * @property Account\Account                                       $account
26
 * @property BetaPrograms\BetaProgramRepositoryInterface           $betaPrograms
27
 * @property Databases\DatabaseRepositoryInterface                 $databases
28
 * @property Databases\DatabaseEngineRepositoryInterface           $databaseEngines
29
 * @property Databases\DatabaseTypeRepositoryInterface             $databaseTypes
30
 * @property Databases\DatabaseMySQLRepositoryInterface            $databasesMySQL
31
 * @property Databases\DatabasePostgreSQLRepositoryInterface       $databasesPostgreSQL
32
 * @property Domains\DomainRepositoryInterface                     $domains
33
 * @property Networking\FirewallRepositoryInterface                $firewalls
34
 * @property Images\ImageRepositoryInterface                       $images
35
 * @property LinodeInstances\KernelRepositoryInterface             $kernels
36
 * @property LinodeInstances\LinodeRepositoryInterface             $linodes
37
 * @property LinodeTypes\LinodeTypeRepositoryInterface             $linodeTypes
38
 * @property LKE\LKEClusterRepositoryInterface                     $lkeClusters
39
 * @property LKE\LKEVersionRepositoryInterface                     $lkeVersions
40
 * @property Longview\LongviewClientRepositoryInterface            $longviewClients
41
 * @property Longview\LongviewSubscriptionRepositoryInterface      $longviewSubscriptions
42
 * @property Managed\ManagedContactRepositoryInterface             $managedContacts
43
 * @property Managed\ManagedCredentialRepositoryInterface          $managedCredentials
44
 * @property Managed\ManagedIssueRepositoryInterface               $managedIssues
45
 * @property Managed\ManagedLinodeSettingsRepositoryInterface      $managedLinodeSettings
46
 * @property Managed\ManagedServiceRepositoryInterface             $managedServices
47
 * @property Networking\IPAddressRepositoryInterface               $ipAddresses
48
 * @property Networking\IPv6PoolRepositoryInterface                $ipv6Pools
49
 * @property Networking\IPv6RangeRepositoryInterface               $ipv6Ranges
50
 * @property NodeBalancers\NodeBalancerRepositoryInterface         $nodeBalancers
51
 * @property ObjectStorage\ObjectStorageClusterRepositoryInterface $objectStorageClusters
52
 * @property ObjectStorage\ObjectStorageKeyRepositoryInterface     $objectStorageKeys
53
 * @property Profile\Profile                                       $profile
54
 * @property Regions\RegionRepositoryInterface                     $regions
55
 * @property StackScripts\StackScriptRepositoryInterface           $stackScripts
56
 * @property Support\SupportTicketRepositoryInterface              $supportTickets
57
 * @property Tags\TagRepositoryInterface                           $tags
58
 * @property Networking\VlansRepositoryInterface                   $vlans
59
 * @property Volumes\VolumeRepositoryInterface                     $volumes
60
 * @property VPC\VPCRepositoryInterface                            $vpcs
61
 */
62
class LinodeClient
63
{
64
    // Request methods.
65
    public const REQUEST_GET    = 'GET';
66
    public const REQUEST_POST   = 'POST';
67
    public const REQUEST_PUT    = 'PUT';
68
    public const REQUEST_DELETE = 'DELETE';
69
70
    // Response success codes.
71
    public const SUCCESS_OK         = 200;
72
    public const SUCCESS_ACCEPTED   = 202;
73
    public const SUCCESS_NO_CONTENT = 204;
74
75
    // Response error codes.
76
    public const ERROR_BAD_REQUEST           = 400;
77
    public const ERROR_UNAUTHORIZED          = 401;
78
    public const ERROR_FORBIDDEN             = 403;
79
    public const ERROR_NOT_FOUND             = 404;
80
    public const ERROR_TOO_MANY_REQUESTS     = 429;
81
    public const ERROR_INTERNAL_SERVER_ERROR = 500;
82
83
    // Base URI to Linode API.
84
    protected const BASE_API_URI = 'https://api.linode.com/v4';
85
86
    /** @var ClientInterface HTTP client. */
87
    protected ClientInterface $client;
88
89
    /**
90
     * @param null|string $access_token API access token (PAT or retrieved via OAuth).
91
     */
92 1
    public function __construct(protected ?string $access_token = null)
93
    {
94 1
        $this->client = new Client();
95
    }
96
97
    /**
98
     * Returns specified repository.
99
     *
100
     * @param string $name Repository name.
101
     *
102
     * @throws LinodeException
103
     */
104 1
    public function __get(string $name): null|Account\Account|Profile\Profile|RepositoryInterface
105
    {
106 1
        return match ($name) {
107 1
            'account'               => new Account\Account($this),
108 1
            'betaPrograms'          => new BetaPrograms\Repository\BetaProgramRepository($this),
109 1
            'databases'             => new Databases\Repository\DatabaseRepository($this),
110 1
            'databaseEngines'       => new Databases\Repository\DatabaseEngineRepository($this),
111 1
            'databaseTypes'         => new Databases\Repository\DatabaseTypeRepository($this),
112 1
            'databasesMySQL'        => new Databases\Repository\DatabaseMySQLRepository($this),
113 1
            'databasesPostgreSQL'   => new Databases\Repository\DatabasePostgreSQLRepository($this),
114 1
            'domains'               => new Domains\Repository\DomainRepository($this),
115 1
            'firewalls'             => new Networking\Repository\FirewallRepository($this),
116 1
            'images'                => new Images\Repository\ImageRepository($this),
117 1
            'kernels'               => new LinodeInstances\Repository\KernelRepository($this),
118 1
            'linodes'               => new LinodeInstances\Repository\LinodeRepository($this),
119 1
            'linodeTypes'           => new LinodeTypes\Repository\LinodeTypeRepository($this),
120 1
            'lkeClusters'           => new LKE\Repository\LKEClusterRepository($this),
121 1
            'lkeVersions'           => new LKE\Repository\LKEVersionRepository($this),
122 1
            'longviewClients'       => new Longview\Repository\LongviewClientRepository($this),
123 1
            'longviewSubscriptions' => new Longview\Repository\LongviewSubscriptionRepository($this),
124 1
            'managedContacts'       => new Managed\Repository\ManagedContactRepository($this),
125 1
            'managedCredentials'    => new Managed\Repository\ManagedCredentialRepository($this),
126 1
            'managedIssues'         => new Managed\Repository\ManagedIssueRepository($this),
127 1
            'managedLinodeSettings' => new Managed\Repository\ManagedLinodeSettingsRepository($this),
128 1
            'managedServices'       => new Managed\Repository\ManagedServiceRepository($this),
129 1
            'ipAddresses'           => new Networking\Repository\IPAddressRepository($this),
130 1
            'ipv6Pools'             => new Networking\Repository\IPv6PoolRepository($this),
131 1
            'ipv6Ranges'            => new Networking\Repository\IPv6RangeRepository($this),
132 1
            'nodeBalancers'         => new NodeBalancers\Repository\NodeBalancerRepository($this),
133 1
            'objectStorageClusters' => new ObjectStorage\Repository\ObjectStorageClusterRepository($this),
134 1
            'objectStorageKeys'     => new ObjectStorage\Repository\ObjectStorageKeyRepository($this),
135 1
            'profile'               => new Profile\Profile($this),
136 1
            'regions'               => new Regions\Repository\RegionRepository($this),
137 1
            'stackScripts'          => new StackScripts\Repository\StackScriptRepository($this),
138 1
            'supportTickets'        => new Support\Repository\SupportTicketRepository($this),
139 1
            'tags'                  => new Tags\Repository\TagRepository($this),
140 1
            'vlans'                 => new Networking\Repository\VlansRepository($this),
141 1
            'volumes'               => new Volumes\Repository\VolumeRepository($this),
142 1
            'vpcs'                  => new VPC\Repository\VPCRepository($this),
143 1
            default                 => null,
144 1
        };
145
    }
146
147
    /**
148
     * Performs a GET request to specified API endpoint.
149
     *
150
     * @param string $uri     Relative URI to the API endpoint.
151
     * @param array  $body    Request body.
152
     * @param array  $filters Pagination options.
153
     *
154
     * @throws LinodeException
155
     */
156 2
    public function get(string $uri, array $body = [], array $filters = []): ResponseInterface
157
    {
158 2
        $options = [];
159
160 2
        if (0 !== count($filters)) {
161 2
            $options['headers']['X-Filter'] = json_encode($filters);
162
        }
163
164 2
        if (0 !== count($body)) {
165 2
            $options['query'] = $body;
166
        }
167
168 2
        return $this->api(self::REQUEST_GET, $uri, $options);
169
    }
170
171
    /**
172
     * Performs a POST request to specified API endpoint.
173
     *
174
     * @param string $uri     Relative URI to the API endpoint.
175
     * @param array  $body    Request body.
176
     * @param array  $options Custom request options.
177
     *
178
     * @throws LinodeException
179
     */
180 1
    public function post(string $uri, array $body = [], array $options = []): ResponseInterface
181
    {
182 1
        if (0 !== count($body) && 0 === count($options)) {
183 1
            $options['json'] = array_filter($body, static fn ($value) => null !== $value);
184
        }
185
186 1
        return $this->api(self::REQUEST_POST, $uri, $options);
187
    }
188
189
    /**
190
     * Performs a PUT request to specified API endpoint.
191
     *
192
     * @param string $uri     Relative URI to the API endpoint.
193
     * @param array  $body    Request body.
194
     * @param array  $options Custom request options.
195
     *
196
     * @throws LinodeException
197
     */
198 1
    public function put(string $uri, array $body = [], array $options = []): ResponseInterface
199
    {
200 1
        if (0 !== count($body) && 0 === count($options)) {
201 1
            $options['json'] = array_filter($body, static fn ($value) => null !== $value);
202
        }
203
204 1
        return $this->api(self::REQUEST_PUT, $uri, $options);
205
    }
206
207
    /**
208
     * Performs a DELETE request to specified API endpoint.
209
     *
210
     * @param string $uri Relative URI to the API endpoint.
211
     *
212
     * @throws LinodeException
213
     */
214 1
    public function delete(string $uri): ResponseInterface
215
    {
216 1
        return $this->api(self::REQUEST_DELETE, $uri);
217
    }
218
219
    /**
220
     * Performs a request to specified API endpoint.
221
     *
222
     * @param string $method  Request method.
223
     * @param string $uri     Relative URI to request bodyAPI endpoint.
224
     * @param array  $options Request options.
225
     *
226
     * @throws LinodeException
227
     */
228 2
    protected function api(string $method, string $uri, array $options = []): ResponseInterface
229
    {
230
        try {
231 2
            if (null !== $this->access_token) {
232 2
                $options['headers']['Authorization'] = 'Bearer ' . $this->access_token;
233
            }
234
235 2
            return $this->client->request($method, self::BASE_API_URI . $uri, $options);
236 2
        } catch (ClientException $exception) {
237 1
            throw new LinodeException($exception->getResponse());
238 1
        } catch (GuzzleException) {
239 1
            throw new LinodeException(new Response(500));
240
        }
241
    }
242
}
243