Passed
Branch feature/first-release (57b0a8)
by Andrea Marco
13:40
created

Config::concurrency()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Cerbero\LazyJsonPages;
4
5
use Cerbero\LazyJson\Concerns\EndpointAware;
6
use Cerbero\LazyJsonPages\Exceptions\LazyJsonPagesException;
7
use Illuminate\Support\Str;
8
9
/**
10
 * The APIs configuration.
11
 *
12
 */
13
class Config
14
{
15
    use EndpointAware;
16
17
    /**
18
     * The source wrapper.
19
     *
20
     * @var SourceWrapper
21
     */
22
    public $source;
23
24
    /**
25
     * The path to extract items from.
26
     *
27
     * @var string
28
     */
29
    public $path;
30
31
    /**
32
     * The name of the page.
33
     *
34
     * @var string
35
     */
36
    public $pageName = 'page';
37
38
    /**
39
     * The number of the first page.
40
     *
41
     * @var int
42
     */
43
    public $firstPage = 1;
44
45
    /**
46
     * The total number of pages.
47
     *
48
     * @var int
49
     */
50
    public $pages;
51
52
    /**
53
     * The total number of items.
54
     *
55
     * @var int
56
     */
57
    public $items;
58
59
    /**
60
     * The number of items per page.
61
     *
62
     * @var int
63
     */
64
    public $perPage;
65
66
    /**
67
     * The query parameter holding the number of items per page.
68
     *
69
     * @var string
70
     */
71
    public $perPageQuery;
72
73
    /**
74
     * The new number of items per page.
75
     *
76
     * @var int
77
     */
78
    public $perPageOverride;
79
80
    /**
81
     * The next page of a simple or cursor pagination.
82
     *
83
     * @var string|int
84
     */
85
    public $nextPage;
86
87
    /**
88
     * The key holding the next page.
89
     *
90
     * @var string
91
     */
92
    public $nextPageKey;
93
94
    /**
95
     * The number of the last page.
96
     *
97
     * @var int
98
     */
99
    public $lastPage;
100
101
    /**
102
     * The number of pages to fetch per chunk.
103
     *
104
     * @var int
105
     */
106
    public $chunk;
107
108
    /**
109
     * The maximum number of concurrent async HTTP requests.
110
     *
111
     * @var int
112
     */
113
    public $concurrency = 10;
114
115
    /**
116
     * The timeout in seconds.
117
     *
118
     * @var int
119
     */
120
    public $timeout = 5;
121
122
    /**
123
     * The number of attempts to fetch pages.
124
     *
125
     * @var int
126
     */
127
    public $attempts = 3;
128
129
    /**
130
     * The backoff strategy.
131
     *
132
     * @var callable
133
     */
134
    public $backoff;
135
136
    /**
137
     * Instantiate the class.
138
     *
139
     * @param \Psr\Http\Message\RequestInterface|\Illuminate\Http\Client\Response $source
140
     * @param string $path
141
     * @param callable|array|string|int $config
142
     */
143
    public function __construct($source, string $path, $config)
144
    {
145
        $this->source = new SourceWrapper($source);
146
        $this->path = $path;
147
        $this->hydrateConfig($config);
148
    }
149
150
    /**
151
     * Hydrate the configuration
152
     *
153
     * @param callable|array|string|int $config
154
     * @return void
155
     *
156
     * @throws LazyJsonPagesException
157
     */
158
    protected function hydrateConfig($config): void
159
    {
160
        if (is_callable($config)) {
161
            $config($this);
162
        } elseif (is_array($config)) {
163
            $this->resolveConfig($config);
164
        } elseif (is_string($config) || is_numeric($config)) {
165
            $this->pages($config);
166
        } else {
167
            throw new LazyJsonPagesException('The provided configuration is not valid.');
168
        }
169
    }
170
171
    /**
172
     * Resolve the given configuration
173
     *
174
     * @param array $config
175
     * @return void
176
     *
177
     * @throws LazyJsonPagesException
178
     */
179
    protected function resolveConfig(array $config): void
180
    {
181
        foreach ($config as $key => $value) {
182
            if (method_exists($this, $method = Str::camel($key))) {
183
                $values = is_array($value) ? $value : [$value];
184
                call_user_func_array([$this, $method], $values);
185
            } else {
186
                throw new LazyJsonPagesException("The key [{$key}] is not valid.");
187
            }
188
        }
189
    }
190
191
    /**
192
     * Set the page name
193
     *
194
     * @param string $name
195
     * @return self
196
     */
197
    public function pageName(string $name): self
198
    {
199
        $this->pageName = $name;
200
201
        return $this;
202
    }
203
204
    /**
205
     * Set the number of the first page
206
     *
207
     * @param int $page
208
     * @return self
209
     */
210
    public function firstPage(int $page): self
211
    {
212
        $this->firstPage = max(0, $page);
213
214
        return $this;
215
    }
216
217
    /**
218
     * Set the total number of pages
219
     *
220
     * @param string|int $pages
221
     * @return self
222
     */
223
    public function pages($pages): self
224
    {
225
        $this->pages = $this->resolveInt($pages, 1);
226
227
        return $this;
228
    }
229
230
    /**
231
     * Retrieve an integer from the given value
232
     *
233
     * @param string|int $value
234
     * @param int $minimum
235
     * @return int
236
     */
237
    protected function resolveInt($value, int $minimum): int
238
    {
239
        return (int) max($minimum, $this->resolvePage($value));
240
    }
241
242
    /**
243
     * Retrieve the page value from the given presumed URL
244
     *
245
     * @param mixed $value
246
     * @return mixed
247
     */
248
    protected function resolvePage($value)
249
    {
250
        if (is_numeric($value)) {
251
            return (int) $value;
252
        } elseif ($this->isEndpoint($value = $this->source->json($value))) {
253
            parse_str(parse_url($value, PHP_URL_QUERY), $query);
254
            $value = $query[$this->pageName];
255
        }
256
257
        return is_numeric($value) ? (int) $value : $value;
258
    }
259
260
    /**
261
     * Set the total number of items
262
     *
263
     * @param string|int $items
264
     * @return self
265
     */
266
    public function items($items): self
267
    {
268
        $this->items = $this->resolveInt($items, 0);
269
270
        return $this;
271
    }
272
273
    /**
274
     * Set the number of items per page and optionally override it
275
     *
276
     * @param int $perPage
277
     * @param string|null $query
278
     * @param int $firstPageItems
279
     * @return self
280
     */
281
    public function perPage(int $perPage, string $query = null, int $firstPageItems = 1): self
282
    {
283
        $this->perPage = max(1, $query ? $firstPageItems : $perPage);
284
        $this->perPageQuery = $query;
285
        $this->perPageOverride = $query ? max(1, $perPage) : null;
286
287
        return $this;
288
    }
289
290
    /**
291
     * Set the next page
292
     *
293
     * @param string $key
294
     * @return self
295
     */
296
    public function nextPage(string $key): self
297
    {
298
        $this->nextPageKey = $key;
299
        $this->nextPage = $this->resolvePage($key);
300
301
        return $this;
302
    }
303
304
    /**
305
     * Set the number of the last page
306
     *
307
     * @param string|int $page
308
     * @return self
309
     */
310
    public function lastPage($page): self
311
    {
312
        $this->lastPage = $this->resolvePage($page);
313
314
        return $this;
315
    }
316
317
    /**
318
     * Fetch pages synchronously
319
     *
320
     * @return self
321
     */
322
    public function sync(): self
323
    {
324
        return $this->chunk(1);
325
    }
326
327
    /**
328
     * Set the number of pages to fetch per chunk
329
     *
330
     * @param int $size
331
     * @return self
332
     */
333
    public function chunk(int $size): self
334
    {
335
        $this->chunk = max(1, $size);
336
337
        return $this;
338
    }
339
340
    /**
341
     * Set the maximum number of concurrent async HTTP requests
342
     *
343
     * @param int $max
344
     * @return self
345
     */
346
    public function concurrency(int $max): self
347
    {
348
        $this->concurrency = max(0, $max);
349
350
        return $this;
351
    }
352
353
    /**
354
     * Set the timeout in seconds
355
     *
356
     * @param int $seconds
357
     * @return self
358
     */
359
    public function timeout(int $seconds): self
360
    {
361
        $this->timeout = max(0, $seconds);
362
363
        return $this;
364
    }
365
366
    /**
367
     * Set the number of attempts to fetch pages
368
     *
369
     * @param int $times
370
     * @return self
371
     */
372
    public function attempts(int $times): self
373
    {
374
        $this->attempts = max(1, $times);
375
376
        return $this;
377
    }
378
379
    /**
380
     * Set the backoff strategy
381
     *
382
     * @param callable $callback
383
     * @return self
384
     */
385
    public function backoff(callable $callback): self
386
    {
387
        $this->backoff = $callback;
388
389
        return $this;
390
    }
391
}
392