• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

leeqvip / php-apollo / 21219920138

21 Jan 2026 05:48PM UTC coverage: 52.607%. First build
21219920138

push

github

leeqvip
feat: first commit

111 of 211 new or added lines in 9 files covered. (52.61%)

111 of 211 relevant lines covered (52.61%)

6.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.29
/src/Client.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Leeqvip\Apollo;
6

7
use GuzzleHttp\Client as GuzzleClient;
8
use GuzzleHttp\Exception\GuzzleException;
9
use Leeqvip\Apollo\Auths\Auth;
10
use Leeqvip\Apollo\Exceptions\ApolloException;
11
use Leeqvip\Apollo\Traits\FakeClient;
12
use Psr\Http\Message\ResponseInterface;
13

14
/**
15
 * Apollo server communication class
16
 */
17
class Client
18
{
19
    use FakeClient;
20

21
    /**
22
     * Guzzle client
23
     * @var GuzzleClient
24
     */
25
    protected GuzzleClient $httpClient;
26

27
    /**
28
     * Authentication object
29
     * @var Auth
30
     */
31
    protected Auth $auth;
32

33
    /**
34
     * Apollo server URL
35
     * @var string
36
     */
37
    protected string $serverUrl;
38

39
    /**
40
     * Application ID
41
     * @var string
42
     */
43
    protected string $appId;
44

45
    /**
46
     * Cluster
47
     * @var string
48
     */
49
    protected string $cluster;
50

51
    /**
52
     * Secret key for authentication
53
     * @var string
54
     */
55
    protected string $secret = '';
56

57
    /**
58
     * Configuration version
59
     * @var array<string, string>
60
     */
61
    protected array $releaseKeys = [];
62

63
    /**
64
     * @var array<string, int>
65
     */
66
    protected array $notificationId = [];
67

68
    /**
69
     * Constructor
70
     *
71
     * @param array<string, mixed> $config Configuration parameters
72
     */
73
    public function __construct(array $config)
74
    {
75
        $this->serverUrl = $config['server_url'] ?? 'http://localhost:8080';
18✔
76
        $this->appId = $config['app_id'] ?? '';
18✔
77
        $this->cluster = $config['cluster'] ?? 'default';
18✔
78
        $this->secret = $config['secret'] ?? '';
18✔
79

80
        $this->httpClient = new GuzzleClient([
18✔
81
            'base_uri' => $this->serverUrl,
18✔
82
            'timeout' => 60,
18✔
83
            'connect_timeout' => 10,
18✔
84
            'headers' => $this->getHeaders(),
18✔
85
        ]);
18✔
86

87
        $this->auth = new Auth();
18✔
88
    }
89

90
    /**
91
     * Get configuration immediately
92
     *
93
     * @param string $namespace Namespace
94
     * @return array<string, mixed>
95
     * @throws ApolloException
96
     * @throws GuzzleException
97
     */
98
    public function getConfigImmediately(string $namespace): array
99
    {
100
        $uri = '/configs/' . $this->appId . '/' . $this->cluster . '/' . $namespace;
6✔
101
        $query = http_build_query([
6✔
102
            'releaseKey' => $this->releaseKeys[$namespace] ?? '',
6✔
103
            'ip' => $this->getClientIp(),
6✔
104
        ]);
6✔
105
        $uri .= '?' . $query;
6✔
106

107
        $body = $this->get($uri);
6✔
108

109
        var_dump($body);
6✔
110

111
        $data = json_decode($body, true);
6✔
112

113
        if (!isset($data['configurations'])) {
6✔
NEW
114
            throw new ApolloException('Not found configurations key', 400, null, ['body' => $body]);
×
115
        }
116

117
        $this->releaseKeys[$namespace] = $data['releaseKey'];
6✔
118
        return $data['configurations'];
6✔
119
    }
120

121
    /**
122
     * @throws GuzzleException
123
     * @throws ApolloException
124
     */
125
    public function getConfig(string $namespace): string
126
    {
127
        $uri = '/configfiles/json/' . $this->appId . '/' . $this->cluster . '/' . $namespace;
6✔
128
        $query = http_build_query([
6✔
129
            'ip' => $this->getClientIp(),
6✔
130
        ]);
6✔
131
        $uri .= '?' . $query;
6✔
132

133
        return $this->get($uri);
6✔
134
    }
135

136
    /**
137
     * Listen for configuration changes
138
     *
139
     * @param array<string> $namespaces Namespace list
140
     * @param int $timeout Timeout in seconds
141
     * @return array<array<string, mixed>>
142
     * @throws ApolloException
143
     * @throws GuzzleException
144
     */
145
    public function listenConfig(array $namespaces, int $timeout = 60): ?array
146
    {
NEW
147
        $query = [
×
NEW
148
            'appId' => $this->appId,
×
NEW
149
            'cluster' => $this->cluster,
×
NEW
150
            'notifications' => json_encode(array_map(function (string $namespace) {
×
NEW
151
                return [
×
NEW
152
                    'namespaceName' => $namespace,
×
NEW
153
                    'notificationId' => $this->getNotificationId($namespace),
×
NEW
154
                ];
×
NEW
155
            }, $namespaces))
×
NEW
156
        ];
×
NEW
157
        $url = '/notifications/v2?' . http_build_query($query);
×
NEW
158
        $body = $this->get($url, [
×
NEW
159
            'timeout' => $timeout + 10,
×
NEW
160
        ]);
×
161

NEW
162
        return json_decode($body, true);
×
163
    }
164

165
    /**
166
     * Get client IP
167
     *
168
     * @return string
169
     */
170
    protected function getClientIp(): string
171
    {
172
        $ipKeys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'];
12✔
173

174
        foreach ($ipKeys as $key) {
12✔
175
            if (!empty($_SERVER[$key])) {
12✔
NEW
176
                $ip = trim($_SERVER[$key]);
×
NEW
177
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
×
NEW
178
                    return $ip;
×
179
                }
180
            }
181
        }
182

183
        return '127.0.0.1';
12✔
184
    }
185

186
    /**
187
     * Get HTTP headers
188
     *
189
     * @return array<string, string>
190
     */
191
    protected function getHeaders(): array
192
    {
193
        return [
18✔
194
            'Content-Type' => 'application/json',
18✔
195
            'Accept' => 'application/json',
18✔
196
        ];
18✔
197
    }
198

199
    /**
200
     * @param string $uri
201
     * @param array $options
202
     * @return string
203
     * @throws ApolloException
204
     * @throws GuzzleException
205
     */
206
    public function get(string $uri, array $options = []): string
207
    {
208
        $authHeaders = $this->auth->headers($uri, $this->appId, $this->secret);
12✔
209

210
        $options['headers'] = array_merge($this->getHeaders(), $options['headers'] ?? [], $authHeaders);
12✔
211

212
        $response = $this->httpGet($uri, $options);
12✔
213

214
        if ($response->getStatusCode() >= 400) {
12✔
NEW
215
            throw new ApolloException('Request failed with status code ' . $response->getStatusCode(), 400, null, ['response' => $response->getBody()]);
×
216
        }
217

218
        return $response->getBody()->getContents();
12✔
219
    }
220

221
    /**
222
     * @throws GuzzleException
223
     */
224
    protected function httpGet(string $uri, array $options = []): ResponseInterface
225
    {
226
        $fakeResponse = $this->fakeGet($uri, $options);
12✔
227
        if ($fakeResponse) {
12✔
228
            return $fakeResponse;
12✔
229
        }
230

NEW
231
        return $this->httpClient->get($uri, $options);
×
232
    }
233

234
    /**
235
     * Get current release key
236
     *
237
     * @param string $namespace Namespace
238
     * @return string|null
239
     */
240
    public function getReleaseKey(string $namespace): ?string
241
    {
NEW
242
        return $this->releaseKeys[$namespace] ?? null;
×
243
    }
244

245
    /**
246
     * Set release key
247
     *
248
     * @param string $namespace Namespace
249
     * @param string $releaseKey Release key
250
     * @return void
251
     */
252
    public function setReleaseKey(string $namespace, string $releaseKey): void
253
    {
NEW
254
        $this->releaseKeys[$namespace] = $releaseKey;
×
255
    }
256

257
    public function getNotificationId(string $namespace): int
258
    {
NEW
259
        return $this->notificationId[$namespace] ?? -1;
×
260
    }
261

262

263
    public function setNotificationId(string $namespace, int $notificationId): void
264
    {
NEW
265
        $this->notificationId[$namespace] = $notificationId;
×
266
    }
267
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc