Completed
Pull Request — master (#226)
by Sergey
02:25
created

Pagination::reachesLimit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 2
eloc 2
nc 2
nop 1
1
<?php
2
3
namespace seregazhuk\PinterestBot\Helpers;
4
5
use Traversable;
6
use seregazhuk\PinterestBot\Api\Contracts\PaginatedResponse;
7
8
/**
9
 * Class Pagination
10
 * Iterate through results of Pinterest Api. By default iterator will return 50 first
11
 * pagination results. To change this behaviour specify another limit as the
12
 * constructor param. For no limits specify zero.
13
 *
14
 * @package seregazhuk\PinterestBot\Helpers
15
 */
16
class Pagination implements \IteratorAggregate
17
{
18
    const DEFAULT_LIMIT = 50;
19
20
    /**
21
     * @var int
22
     */
23
    protected $limit;
24
25
    /**
26
     * @var array
27
     */
28
    protected $bookmarks = [];
29
30
    /**
31
     * @var callable
32
     */
33
    protected $callback;
34
35
    /**
36
     * @var int
37
     */
38
    protected $offset;
39
40
    /**
41
     * @param int $limit
42
     */
43
    public function __construct($limit = self::DEFAULT_LIMIT)
44
    {
45
        $this->limit = $limit;
46
    }
47
48
    /**
49
     * Sets a callback to make requests. Should be a closure
50
     * that accepts a $bookmarks array as an argument.
51
     *
52
     * @param callable $callback
53
     * @return $this
54
     */
55
    public function paginateOver(callable $callback)
56
    {
57
        $this->callback = $callback;
58
59
        return $this;
60
    }
61
62
    /**
63
     * Syntax sugar for getIterator method
64
     * @return Traversable
65
     */
66
    public function get()
67
    {
68
        return $this->getIterator();
69
    }
70
71
    /**
72
     * Retrieve an external iterator
73
     * @return Traversable
74
     */
75
    public function getIterator()
76
    {
77
        $resultsNum = 0;
78
79
        while (true) {
80
            $results = $this->getCurrentResults();
81
82
            if (empty($results)) return;
83
84
            foreach ($results as $result) {
0 ignored issues
show
Bug introduced by
The expression $results of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
85
                $resultsNum++;
86
87
                if($resultsNum > $this->offset) yield $result;
88
89
                if ($this->paginationFinished($resultsNum)) return;
90
            }
91
        }
92
    }
93
94
    /**
95
     * @param int $offset
96
     * @return $this
97
     */
98
    public function skip($offset)
99
    {
100
        $this->offset = $offset;
101
102
        return $this;
103
    }
104
105
    /**
106
     * @return array
107
     */
108
    public function toArray()
109
    {
110
        return iterator_to_array($this->getIterator());
111
    }
112
113
    /**
114
     * @return array
115
     */
116
    protected function getCurrentResults()
117
    {
118
        $callback = $this->callback;
119
120
        $response = $callback($this->bookmarks);
121
122
        return $this->processResponse($response);
123
    }
124
125
    /**
126
     * @param PaginatedResponse $response
127
     * @return array
128
     */
129
    protected function processResponse(PaginatedResponse $response)
130
    {
131
        if ($response->isEmpty()) return [];
132
133
        $this->bookmarks = $response->getBookmarks();
134
135
        return $response->getResponseData();
136
    }
137
138
    /**
139
     * @param int $resultsNum
140
     * @return bool
141
     */
142
    protected function paginationFinished($resultsNum)
143
    {
144
        return $this->reachesLimit($resultsNum) || $this->checkEndBookMarks();
145
    }
146
147
    /**
148
     * Check if we get results limit in pagination.
149
     *
150
     * @param int $resultsNum
151
     *
152
     * @return bool
153
     */
154
    protected function reachesLimit($resultsNum)
155
    {
156
        return $this->limit && $resultsNum >= $this->limit;
157
    }
158
159
160
    /**
161
     * Checks for -end- substring in bookmarks. This is pinterest sign of
162
     * the finished pagination.
163
     *
164
     * @return bool
165
     */
166
    protected function checkEndBookMarks()
167
    {
168
        return !empty($this->bookmarks) && $this->bookmarks[0] == '-end-';
169
    }
170
}
171