Completed
Push — master ( 039234...be6e2d )
by ignace nyamagana
02:35
created

Statement::filterColumnAgainstCsvHeader()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 12
cts 12
cp 1
rs 8.5906
c 0
b 0
f 0
cc 6
eloc 12
nc 5
nop 1
crap 6
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 trait to manage filtering a CSV
24
 *
25
 * @package League.csv
26
 * @since   9.0.0
27
 * @author  Ignace Nyamagana Butera <[email protected]>
28
 *
29
 */
30
class Statement
31
{
32
    use ValidatorTrait;
33
34
    /**
35
     * Callables to filter the iterator
36
     *
37
     * @var callable[]
38
     */
39
    protected $where = [];
40
41
    /**
42
     * Callables to sort the iterator
43
     *
44
     * @var callable[]
45
     */
46
    protected $order_by = [];
47
48
    /**
49
     * iterator Offset
50
     *
51
     * @var int
52
     */
53
    protected $offset = 0;
54
55
    /**
56
     * iterator maximum length
57
     *
58
     * @var int
59
     */
60
    protected $limit = -1;
61
62
    /**
63
     * Set the Iterator filter method
64
     *
65
     * @param callable $callable
66
     *
67
     * @return self
68
     */
69 2
    public function where(callable $callable): self
70
    {
71 2
        $clone = clone $this;
72 2
        $clone->where[] = $callable;
73
74 2
        return $clone;
75
    }
76
77
    /**
78
     * Set an Iterator sorting callable function
79
     *
80
     * @param callable $callable
81
     *
82
     * @return self
83
     */
84 2
    public function orderBy(callable $callable): self
85
    {
86 2
        $clone = clone $this;
87 2
        $clone->order_by[] = $callable;
88
89 2
        return $clone;
90
    }
91
92
    /**
93
     * Set LimitIterator Offset
94
     *
95
     * @param $offset
96
     *
97
     * @return self
98
     */
99 18
    public function offset(int $offset): self
100
    {
101 18
        $offset = $this->filterMinRange($offset, 0, 'The Statement offset must be a positive integer or 0');
102 18
        if ($offset === $this->offset) {
103 2
            return $this;
104
        }
105
106 16
        $clone = clone $this;
107 16
        $clone->offset = $offset;
108
109 16
        return $clone;
110
    }
111
112
    /**
113
     * Set LimitIterator Count
114
     *
115
     * @param int $limit
116
     *
117
     * @return self
118
     */
119 22
    public function limit(int $limit): self
120
    {
121 22
        $limit = $this->filterMinRange($limit, -1, 'The Statement limit must an integer greater or equals to -1');
122 20
        if ($limit === $this->limit) {
123 2
            return $this;
124
        }
125
126 18
        $clone = clone $this;
127 18
        $clone->limit = $limit;
128
129 18
        return $clone;
130
    }
131
132
    /**
133
     * Returns the inner CSV Document Iterator object
134
     *
135
     * @param Reader $reader
136
     *
137
     * @return RecordSet
138
     */
139 100
    public function process(Reader $reader): RecordSet
140
    {
141 100
        $iterator = $this->buildWhere($reader->getIterator());
0 ignored issues
show
Compatibility introduced by
$reader->getIterator() of type object<Traversable> is not a sub-type of object<Iterator>. It seems like you assume a child interface of the interface Traversable to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
142 98
        $iterator = $this->buildOrderBy($iterator);
143 98
        $iterator = new LimitIterator($iterator, $this->offset, $this->limit);
144
145 98
        return new RecordSet($iterator, $reader->getHeader());
146
    }
147
148
    /**
149
    * Filter the Iterator
150
    *
151
    * @param Iterator $iterator
152
    *
153
    * @return Iterator
154
    */
155 98
    protected function buildWhere(Iterator $iterator): Iterator
156
    {
157
        $reducer = function (Iterator $iterator, callable $callable): Iterator {
158 2
            return new CallbackFilterIterator($iterator, $callable);
159 49
        };
160
161 98
        return array_reduce($this->where, $reducer, $iterator);
162
    }
163
164
    /**
165
    * Sort the Iterator
166
    *
167
    * @param Iterator $iterator
168
    *
169
    * @return Iterator
170
    */
171 98
    protected function buildOrderBy(Iterator $iterator): Iterator
172
    {
173 98
        if (empty($this->order_by)) {
174 96
            return $iterator;
175
        }
176
177 2
        $compare = function (array $record_a, array $record_b): int {
178 2
            foreach ($this->order_by as $callable) {
179 2
                if (0 !== ($cmp = $callable($record_a, $record_b))) {
180 2
                    return $cmp;
181
                }
182
            }
183
184
            return $cmp ?? 0;
185 1
        };
186
187 2
        $iterator = new ArrayIterator(iterator_to_array($iterator, true));
188 2
        $iterator->uasort($compare);
189
190 2
        return $iterator;
191
    }
192
}
193