Cursor::hasNext()   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
nc 1
nop 0
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Signifly\Shopify\REST;
4
5
use Illuminate\Support\Arr;
6
use Illuminate\Support\Collection;
7
use Illuminate\Support\Str;
8
use Iterator;
9
use RuntimeException;
10
use Signifly\Shopify\Shopify;
11
12
class Cursor implements Iterator
13
{
14
    const LINK_REGEX = '/<(.*page_info=([a-z0-9\-]+).*)>; rel="?{type}"?/i';
15
16
    protected Shopify $shopify;
17
    protected int $position = 0;
18
    protected array $links = [];
19
    protected array $results = [];
20
    protected string $resourceClass;
21
22
    public function __construct(Shopify $shopify, Collection $results)
23
    {
24
        $this->shopify = $shopify;
25
        $this->results[$this->position] = $results;
26
27
        $this->detectResourceClass();
28
        $this->extractLinks();
29
    }
30
31
    public function current(): Collection
32
    {
33
        return $this->results[$this->position];
34
    }
35
36
    public function hasNext(): bool
37
    {
38
        return ! empty($this->links['next']);
39
    }
40
41
    public function hasPrev(): bool
42
    {
43
        return $this->position > 0;
44
    }
45
46
    public function key(): int
47
    {
48
        return $this->position;
49
    }
50
51
    public function next(): void
52
    {
53
        $this->position++;
54
55
        if (! $this->valid() && $this->hasNext()) {
56
            $this->results[$this->position] = $this->fetchNextResults();
57
            $this->extractLinks();
58
        }
59
    }
60
61
    public function prev(): void
62
    {
63
        if (! $this->hasPrev()) {
64
            throw new RuntimeException('No previous results available.');
65
        }
66
67
        $this->position--;
68
    }
69
70
    public function rewind(): void
71
    {
72
        $this->position = 0;
73
    }
74
75
    public function valid(): bool
76
    {
77
        return isset($this->results[$this->position]);
78
    }
79
80
    protected function extractLinks(): void
81
    {
82
        $response = $this->shopify->getLastResponse();
83
84
        if (! $response->header('Link')) {
85
            $this->links = [];
86
87
            return;
88
        }
89
90
        $links = [
91
            'next' => null,
92
            'previous' => null,
93
        ];
94
95
        foreach (array_keys($links) as $type) {
96
            $matched = preg_match(
97
                str_replace('{type}', $type, static::LINK_REGEX),
98
                $response->header('Link'),
99
                $matches
100
            );
101
102
            if ($matched) {
103
                $links[$type] = $matches[1];
104
            }
105
        }
106
107
        $this->links = $links;
108
    }
109
110
    protected function fetchNextResults(): Collection
111
    {
112
        $response = $this->shopify->get(
113
            Str::after($this->links['next'], $this->shopify->getBaseUrl())
114
        );
115
116
        return Collection::make(Arr::first($response->json()))
117
            ->map(fn ($attr) => new $this->resourceClass($attr, $this->shopify));
118
    }
119
120
    private function detectResourceClass()
121
    {
122
        if ($resource = optional($this->results[0])->first()) {
123
            $this->resourceClass = get_class($resource);
124
        }
125
    }
126
}
127