Completed
Push — master ( fcab5b...f5b5f6 )
by ignace nyamagana
03:43
created

Statement::filter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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