Completed
Pull Request — master (#376)
by ignace nyamagana
01:47
created

Statement::process()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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