Completed
Push — master ( 93b826...c2eec1 )
by Taosikai
11:32
created

CursorBasedPagination::hasPrev()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Slince\Shopify\Common;
4
5
use GuzzleHttp\Psr7\Request;
6
use Psr\Http\Message\ResponseInterface;
7
use Slince\Shopify\Client;
8
use Slince\Shopify\Common\Manager\ManagerInterface;
9
use Slince\Shopify\Common\Model\ModelInterface;
10
use Slince\Shopify\Exception\RuntimeException;
11
12
class CursorBasedPagination
13
{
14
    const LINK_REGEX = '/<(.*page_info=([a-z0-9\-]+).*)>; rel="?{type}"?/i';
15
16
    /**
17
     * @var string
18
     */
19
    protected $resource;
20
21
    /**
22
     * @var array
23
     */
24
    protected $query;
25
26
    /**
27
     * @var ManagerInterface
28
     */
29
    protected $manager;
30
31
    /**
32
     * @var Client
33
     */
34
    protected $client;
35
36
    /**
37
     * @var array
38
     */
39
    protected $links = [];
40
41
    public function __construct(ManagerInterface $manager, $resource, $query)
42
    {
43
        $this->manager = $manager;
44
        $this->client = $manager->getClient();
45
        $this->resource = $resource;
46
        $this->query = $query;
47
    }
48
49
    /**
50
     * Gets the current page data.
51
     *
52
     * @return ModelInterface[]
53
     */
54
    public function current()
55
    {
56
        $data = $this->client->get($this->resource, $this->query);
57
        $this->links = $this->extractHeaderLink($this->client->getLastResponse());
58
        return $this->manager->createMany(reset($data));
59
    }
60
61
    /**
62
     * Get the next page of data.
63
     *
64
     * @return ModelInterface[]
65
     */
66
    public function next()
67
    {
68
        if (!$this->hasNext()) {
69
            throw new RuntimeException("There's no next page");
70
        }
71
72
        return $this->fetchResource($this->links['next']);
73
    }
74
75
    /**
76
     * Checks whether has next page.
77
     *
78
     * @return bool
79
     */
80
    public function hasNext()
81
    {
82
        return !empty($this->links['next']);
83
    }
84
85
    /**
86
     * Get the previous page of data.
87
     *
88
     * @return ModelInterface[]
89
     */
90
    public function prev()
91
    {
92
        if (!$this->hasNext()) {
93
            throw new RuntimeException("There's no previous page");
94
        }
95
        return $this->fetchResource($this->links['previous']);
96
    }
97
98
    /**
99
     * Checks whether has previous page.
100
     *
101
     * @return bool
102
     */
103
    public function hasPrev()
104
    {
105
        return !empty($this->links['previous']);
106
    }
107
108
    protected function fetchResource($url)
109
    {
110
        $request = new Request('GET', $url, [
111
            'Content-Type' => 'application/json',
112
        ]);
113
        $response = $this->client->sendRequest($request);
114
        $data = \GuzzleHttp\json_decode((string)$response->getBody(), true);
115
        $this->links = $this->extractHeaderLink($this->client->getLastResponse());
116
        return $this->manager->createMany(reset($data));
117
    }
118
119
    protected function extractHeaderLink(ResponseInterface $response)
120
    {
121
        if (!$response->hasHeader('Link')) {
122
            return [];
123
        }
124
        $links = [
125
            'next'     => null,
126
            'previous' => null,
127
        ];
128
        foreach (array_keys($links) as $type) {
129
            $matched = preg_match(
130
                str_replace('{type}', $type, static::LINK_REGEX),
131
                $response->getHeader('Link')[0],
132
                $matches
133
            );
134
            if ($matched) {
135
                $links[$type] = $matches[1];
136
            }
137
        }
138
        return $links;
139
    }
140
}