Completed
Push — master ( 5d8a48...562277 )
by ignace nyamagana
13s queued 11s
created

Statement::limit()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 0
loc 15
ccs 8
cts 8
cp 1
crap 3
rs 9.7666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * League.Csv (https://csv.thephpleague.com)
5
 *
6
 * (c) Ignace Nyamagana Butera <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace League\Csv;
15
16
use ArrayIterator;
17
use CallbackFilterIterator;
18
use Iterator;
19
use LimitIterator;
20
use function array_reduce;
21
use function iterator_to_array;
22
23
/**
24
 * Criteria to filter a {@link Reader} object.
25
 */
26
class Statement
27
{
28
    /**
29
     * Callables to filter the iterator.
30
     *
31
     * @var callable[]
32
     */
33
    protected $where = [];
34
35
    /**
36
     * Callables to sort the iterator.
37
     *
38
     * @var callable[]
39
     */
40
    protected $order_by = [];
41
42
    /**
43
     * iterator Offset.
44
     *
45
     * @var int
46
     */
47
    protected $offset = 0;
48
49
    /**
50
     * iterator maximum length.
51
     *
52
     * @var int
53
     */
54
    protected $limit = -1;
55
56
    /**
57
     * Set the Iterator filter method.
58
     */
59 3
    public function where(callable $callable): self
60
    {
61 3
        $clone = clone $this;
62 3
        $clone->where[] = $callable;
63
64 3
        return $clone;
65
    }
66
67
    /**
68
     * Set an Iterator sorting callable function.
69
     */
70 6
    public function orderBy(callable $callable): self
71
    {
72 6
        $clone = clone $this;
73 6
        $clone->order_by[] = $callable;
74
75 6
        return $clone;
76
    }
77
78
    /**
79
     * Set LimitIterator Offset.
80
     *
81
     * @throws Exception if the offset is lesser than 0
82
     */
83 18
    public function offset(int $offset): self
84
    {
85 18
        if (0 > $offset) {
86 3
            throw new InvalidArgument(sprintf('%s() expects the offset to be a positive integer or 0, %s given', __METHOD__, $offset));
87
        }
88
89 15
        if ($offset === $this->offset) {
90 3
            return $this;
91
        }
92
93 12
        $clone = clone $this;
94 12
        $clone->offset = $offset;
95
96 12
        return $clone;
97
    }
98
99
    /**
100
     * Set LimitIterator Count.
101
     *
102
     * @throws Exception if the limit is lesser than -1
103
     */
104 39
    public function limit(int $limit): self
105
    {
106 39
        if (-1 > $limit) {
107 6
            throw new InvalidArgument(sprintf('%s() expects the limit to be greater or equal to -1, %s given', __METHOD__, $limit));
108
        }
109
110 33
        if ($limit === $this->limit) {
111 3
            return $this;
112
        }
113
114 30
        $clone = clone $this;
115 30
        $clone->limit = $limit;
116
117 30
        return $clone;
118
    }
119
120
    /**
121
     * Execute the prepared Statement on the {@link Reader} object.
122
     *
123
     * @param string[] $header an optional header to use instead of the CSV document header
124
     */
125 27
    public function process(Reader $csv, array $header = []): ResultSet
126
    {
127 27
        if ([] === $header) {
128 27
            $header = $csv->getHeader();
129
        }
130
131 27
        $iterator = array_reduce($this->where, [$this, 'filter'], $csv->getRecords($header));
132 27
        $iterator = $this->buildOrderBy($iterator);
133
134 27
        return new ResultSet(new LimitIterator($iterator, $this->offset, $this->limit), $header);
135
    }
136
137
    /**
138
     * Filters elements of an Iterator using a callback function.
139
     */
140 6
    protected function filter(Iterator $iterator, callable $callable): CallbackFilterIterator
141
    {
142 6
        return new CallbackFilterIterator($iterator, $callable);
143
    }
144
145
    /**
146
     * Sort the Iterator.
147
     */
148 21
    protected function buildOrderBy(Iterator $iterator): Iterator
149
    {
150 21
        if ([] === $this->order_by) {
151 15
            return $iterator;
152
        }
153
154
        $compare = function (array $record_a, array $record_b): int {
155 6
            foreach ($this->order_by as $callable) {
156 6
                if (0 !== ($cmp = $callable($record_a, $record_b))) {
157 3
                    return $cmp;
158
                }
159
            }
160
161 3
            return $cmp ?? 0;
162 6
        };
163
164 6
        $iterator = new ArrayIterator(iterator_to_array($iterator));
165 6
        $iterator->uasort($compare);
166
167 6
        return $iterator;
168
    }
169
}
170