PrivateGitHubLoader   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 130
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 54
c 1
b 0
f 0
dl 0
loc 130
rs 10
wmc 19

9 Methods

Rating   Name   Duplication   Size   Complexity  
A assertHealth() 0 6 2
A getHeaders() 0 5 1
A load() 0 27 6
A write() 0 10 1
A getUrl() 0 3 1
A getCacheKey() 0 3 1
A setClient() 0 3 1
A fromConfigArray() 0 19 5
A __construct() 0 6 1
1
<?php
2
3
namespace Startwind\Forrest\Adapter\Loader;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\Exception\ClientException;
7
use GuzzleHttp\RequestOptions;
8
9
/**
10
 * @see https://docs.github.com/de/rest/repos/contents?apiVersion=2022-11-28#create-a-file
11
 */
12
class PrivateGitHubLoader implements Loader, HttpAwareLoader, WritableLoader, CachableLoader
13
{
14
    private const GIT_HUB_API_ENDPOINT = 'https://api.github.com/repos/%s/%s/contents/%s';
15
16
    private string $file;
17
    private string $token;
18
19
    private ?Client $client = null;
20
    private string $user;
21
    private string $repository;
22
23
    private array $fileInformation = [];
24
25
    public function __construct(string $user, string $repository, string $file, string $token)
26
    {
27
        $this->file = $file;
28
        $this->token = $token;
29
        $this->repository = $repository;
30
        $this->user = $user;
31
    }
32
33
    /**
34
     * @inheritDoc
35
     */
36
    public static function fromConfigArray(array $config): Loader
37
    {
38
        if (!array_key_exists('user', $config)) {
39
            throw new \RuntimeException('Missing config field "name" missing.');
40
        }
41
42
        if (!array_key_exists('repository', $config)) {
43
            throw new \RuntimeException('Missing config field "repository" missing.');
44
        }
45
46
        if (!array_key_exists('file', $config)) {
47
            throw new \RuntimeException('Missing config field "file" missing.');
48
        }
49
50
        if (!array_key_exists('token', $config)) {
51
            throw new \RuntimeException('Missing config field "token" missing.');
52
        }
53
54
        return new self($config['user'], $config['repository'], $config['file'], $config['token']);
55
    }
56
57
    private function getHeaders(): array
58
    {
59
        return [
60
            'Authorization' => ' token ' . $this->token,
61
            'Accept' => 'application/vnd.github+json'
62
        ];
63
    }
64
65
    private function getUrl(): string
66
    {
67
        return sprintf(self::GIT_HUB_API_ENDPOINT, $this->user, $this->repository, $this->file);
68
    }
69
70
    /**
71
     * @inheritDoc
72
     */
73
    public function load(): string
74
    {
75
        if (is_null($this->client)) {
76
            throw  new \RuntimeException('The client for this loader was not set but is needed. Please call setClient() before the load() function.');
77
        }
78
79
        if (!empty($this->fileInformation)) {
80
            return base64_decode($this->fileInformation['content']);
81
        }
82
83
        try {
84
            $response = $this->client->request('GET', $this->getUrl(), [
85
                'headers' => $this->getHeaders()
86
            ]);
87
        } catch (ClientException $exception) {
88
            if (str_contains($exception->getMessage(), 'Bad credentials')) {
89
                throw new \RuntimeException('Forbidden due to bad credentials. Please check your token.');
90
            } elseif (str_contains($exception->getMessage(), 'Not Found')) {
91
                throw new \RuntimeException('File was not found. Please check the repository and file in your config.');
92
            } else {
93
                throw $exception;
94
            }
95
        }
96
97
        $this->fileInformation = json_decode((string)$response->getBody(), true);
98
99
        return base64_decode($this->fileInformation['content']);
100
    }
101
102
    /**
103
     * @inheritDoc
104
     */
105
    public function write(string $content)
106
    {
107
        $this->load();
108
109
        $this->client->request('PUT', $this->getUrl(), [
0 ignored issues
show
Bug introduced by
The method request() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

109
        $this->client->/** @scrutinizer ignore-call */ 
110
                       request('PUT', $this->getUrl(), [

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
110
            'headers' => $this->getHeaders(),
111
            RequestOptions::JSON => [
112
                'message' => 'updated repository via Forrest CLI',
113
                'content' => base64_encode($content),
114
                'sha' => $this->fileInformation['sha']
115
            ]
116
        ]);
117
    }
118
119
    /**
120
     * @inheritDoc
121
     */
122
    public function setClient(Client $client): void
123
    {
124
        $this->client = $client;
125
    }
126
127
    public function assertHealth(): void
128
    {
129
        try {
130
            $this->client->get('https://api.github.com');
131
        } catch (\Exception $exception) {
132
            throw new \RuntimeException('Cannot connect to the github API. Please check if your computer is online.');
133
        }
134
    }
135
136
    /**
137
     * @inheritDoc
138
     */
139
    public function getCacheKey(): string
140
    {
141
        return md5($this->repository . $this->user . $this->file);
142
    }
143
}
144