GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

LeverPhp::putUpdate()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace ViaWork\LeverPhp;
4
5
use Exception;
6
use GrahamCampbell\GuzzleFactory\GuzzleFactory;
7
use GuzzleHttp\Client as GuzzleClient;
8
use GuzzleHttp\Exception\ClientException;
9
use GuzzleHttp\HandlerStack;
10
use Illuminate\Support\LazyCollection;
11
use Psr\Http\Message\ResponseInterface;
12
use Spatie\GuzzleRateLimiterMiddleware\RateLimiterMiddleware;
13
use Spatie\GuzzleRateLimiterMiddleware\Store;
14
15
class LeverPhp
16
{
17
    const BACKOFF_TIME = 1500;
18
19
    private $leverKey = '';
20
21
    private $endpoint = '';
22
23
    private $client;
24
25
    private $options = [];
26
27
    /**
28
     * LeverPhp constructor.
29
     * @param string|null $leverKey
30
     * @param GuzzleClient|null $client
31
     * @param Store|null $store
32
     */
33
    public function __construct(string $leverKey = null, GuzzleClient $client = null, Store $store = null)
34
    {
35
        $this->leverKey = $leverKey;
36
37
        $stack = HandlerStack::create();
38
39
        $stack->push(DuplicateAggregatorMiddleware::buildQuery());
40
41
        $stack->push(RateLimiterMiddleware::perSecond(10, $store));
42
43
        $this->client = $client ?? GuzzleFactory::make(
44
                [
45
                    'base_uri' => 'https://api.lever.co/v1/',
46
                    'headers' => [
47
                        'Accept' => 'application/json',
48
                    ],
49
                    'auth' => [$leverKey, ''],
50
                    'handler' => $stack,
51
                ],
52
                self::BACKOFF_TIME
53
            );
54
    }
55
56
    private function reset()
57
    {
58
        $this->endpoint = '';
59
        $this->options = [];
60
    }
61
62
    private function post(array $body): ResponseInterface
63
    {
64
        try {
65
            $response = $this->client->post($this->endpoint, $this->options($body));
66
        } catch (ClientException $exception) {
67
            throw $exception;
68
        } finally {
69
            $this->reset();
70
        }
71
72
        return $response;
73
    }
74
75
    private function options($body)
76
    {
77
        if (isset($this->options['query'])) {
78
            $this->options['query'] = preg_replace('/%5B[0-9]%5D/', '',
79
                http_build_query($this->options['query'])
80
            );
81
        }
82
83
        if (isset($this->options['hasFiles'])) {
84
            $options = [];
85
86
            foreach ($body as $key => $item) {
87
88
                // TODO add support for files[] and automate filename and headers fields.
89
                if (in_array($key, ['file', 'files', 'resumeFile'])) {
90
                    $options[] = [
91
                        'name' => $key,
92
                        'contents' => $item['file'],
93
                        'filename' => $item['name'],
94
                        'headers' => ['Content-Type' => $item['type']],
95
                    ];
96
97
                    continue;
98
                }
99
100
                if (is_array($item)) {
101
                    foreach ($item as $subKey => $subItem) {
102
                        if (is_numeric($subKey)) {
103
                            $options[] = ['name' => $key.'[]', 'contents' => $subItem];
104
                        }
105
106
                        if (is_string($subKey)) {
107
                            $options[] = ['name' => "{$key}[{$subKey}]", 'contents' => $subItem];
108
                        }
109
                    }
110
                }
111
112
                if (is_string($item)) {
113
                    $options[] = ['name' => $key, 'contents' => $item];
114
                }
115
            }
116
117
            unset($this->options['hasFiles']);
118
119
            return array_merge(['multipart' => $options], $this->options);
120
        }
121
122
        return array_merge(['json' => $body], $this->options);
123
    }
124
125
    private function get(): ResponseInterface
126
    {
127
        try {
128
            $response = $this->client->get($this->endpoint, $this->options([]));
129
        } catch (ClientException $exception) {
130
            throw $exception;
131
        } finally {
132
            $this->reset();
133
        }
134
135
        return $response;
136
    }
137
138
    private function put(array $body): ResponseInterface
139
    {
140
        try {
141
            $response = $this->client->put($this->endpoint, $this->options($body));
142
        } catch (ClientException $exception) {
143
            throw $exception;
144
        } finally {
145
            $this->reset();
146
        }
147
148
        return $response;
149
    }
150
151
    public function create(array $body, string $method = 'post'): array
152
    {
153
        $response = $this->responseToArray($this->{$method}($body));
154
155
        return $response['data'];
156
    }
157
158
    public function update(array $body): array
159
    {
160
        return $this->create($body);
161
    }
162
163
    public function putUpdate(array $body): array
164
    {
165
        return $this->create($body, 'put');
166
    }
167
168
    /** @return LazyCollection|array */
169
    public function fetch()
170
    {
171
        $response = $this->responseToArray($this->get());
172
173
        if (! array_key_exists('hasNext', $response)) {
174
            return $response['data'];
175
        }
176
177
        return LazyCollection::make(function () use ($response) {
178
            do {
179
                foreach ($response['data'] as $item) {
180
                    yield $item;
181
                }
182
183
                $response['data'] = [];
184
185
                if (! empty($response['next'])) {
186
                    $response = $this->responseToArray(
187
                        $this->postings()->addParameter('offset', $response['next'])->get()
188
                    );
189
                }
190
            } while (count($response['data']) > 0);
191
        });
192
    }
193
194
    public function leverKey(): string
195
    {
196
        return $this->leverKey;
197
    }
198
199
    public function client(): GuzzleClient
200
    {
201
        return $this->client;
202
    }
203
204
    private function responseToArray(ResponseInterface $response): array
205
    {
206
        return json_decode($response->getBody()->getContents(), true);
207
    }
208
209
    public function expand($expandable)
210
    {
211
        return $this->addParameter('expand', $expandable);
212
    }
213
214
    public function performAs(string $userId)
215
    {
216
        return $this->addParameter('perform_as', $userId);
217
    }
218
219
    public function include($includable)
220
    {
221
        return $this->addParameter('include', $includable);
222
    }
223
224
    /**
225
     * @param string $field
226
     * @param string|array $value
227
     * @return $this
228
     */
229
    public function addParameter(string $field, $value)
230
    {
231
        if (! empty($field) && ! empty($value)) {
232
            $value = is_string($value) ? [$value] : $value;
233
234
            $this->options['query'][$field] = array_merge($this->options['query'][$field] ?? [], $value);
235
        }
236
237
        return $this;
238
    }
239
240
    public function opportunities(string $opportunityId = '')
241
    {
242
        $this->endpoint = 'opportunities'.(empty($opportunityId) ? '' : '/'.$opportunityId);
243
244
        return $this;
245
    }
246
247
    public function resumes(string $resumeId = '')
248
    {
249
        $this->endpoint .= '/resumes'.(empty($resumeId) ? '' : '/'.$resumeId);
250
251
        return $this;
252
    }
253
254
    public function download()
255
    {
256
        $this->endpoint .= '/download';
257
258
        return $this->get()->getBody();
259
    }
260
261
    public function offers()
262
    {
263
        // TODO next release.
264
        // $regex = '/^opportunities\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/';
265
        // if (preg_match($regex, $this->endpoint) === 0){
266
        //     throw new Exception('Did not chain methods in correct order.');
267
        // }
268
269
        $this->endpoint .= '/offers';
270
271
        return $this;
272
    }
273
274
    public function stages()
275
    {
276
        // TODO next release.
277
        // $regex = '/^opportunities\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/';
278
        // if (preg_match($regex, $this->endpoint) === 0){
279
        //     throw new Exception('Did not chain methods in correct order.');
280
        // }
281
282
        $this->endpoint .= '/stage';
283
284
        return $this;
285
    }
286
287
    public function postings(string $postingId = '')
288
    {
289
        $this->endpoint = 'postings'.(empty($postingId) ? '' : '/'.$postingId);
290
291
        return $this;
292
    }
293
294
    public function sendConfirmationEmail()
295
    {
296
        return $this->addParameter('send_confirmation_email', 'true');
297
    }
298
299
    public function apply(array $body): array
300
    {
301
        $this->endpoint .= '/apply';
302
303
        return $this->create($body);
304
    }
305
306
    public function state(string $state)
307
    {
308
        if (! in_array($state, ['published', 'internal', 'closed', 'draft', 'pending', 'rejected'])) {
309
            throw new Exception('Not a valid state');
310
        }
311
312
        return $this->addParameter('state', $state);
313
    }
314
315
    /**
316
     * @param array|string $team
317
     * @return $this
318
     */
319
    public function team($team)
320
    {
321
        return $this->addParameter('team', $team);
322
    }
323
324
    /**
325
     * @param array|string $department
326
     * @return $this
327
     */
328
    public function department($department)
329
    {
330
        return $this->addParameter('department', $department);
331
    }
332
333
    /**
334
     * @return $this
335
     */
336
    public function parse()
337
    {
338
        return $this->addParameter('parse', 'true');
339
    }
340
341
    public function hasFiles()
342
    {
343
        $this->options['hasFiles'] = true;
344
345
        return $this;
346
    }
347
348
    /**
349
     * @param array|string $email
350
     * @return $this
351
     */
352
    public function email($email)
353
    {
354
        return $this->addParameter('email', $email);
355
    }
356
357
    /**
358
     * @param array|string $stageId
359
     * @return $this
360
     */
361
    public function stage($stageId)
362
    {
363
        return $this->addParameter('stage_id', $stageId);
364
    }
365
366
    public function archived()
367
    {
368
        $this->endpoint .= '/archived';
369
370
        return $this;
371
    }
372
373
    public function notes(string $noteId = '')
374
    {
375
        $this->endpoint .= '/notes'.(empty($noteId) ? '' : '/'.$noteId);
376
377
        return $this;
378
    }
379
380
    /**
381
     * @param array|string $postingId
382
     * @return $this
383
     */
384
    public function posting($postingId)
385
    {
386
        return $this->addParameter('posting_id', $postingId);
387
    }
388
}
389