Completed
Pull Request — master (#178)
by ignace nyamagana
02:10
created

Statement::__unset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
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 8.1.1
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
namespace League\Csv;
14
15
use ArrayIterator;
16
use CallbackFilterIterator;
17
use InvalidArgumentException;
18
use Iterator;
19
use League\Csv\Config\Validator;
20
use LimitIterator;
21
use OutOfRangeException;
22
23
/**
24
 * A simple Statement class to fetch rows against a Csv file object
25
 *
26
 * @package League.csv
27
 * @since  4.2.1
28
 *
29
 */
30
class Statement
31
{
32
    use Validator;
33
34
    /**
35
     * Callables to filter the iterator
36
     *
37
     * @var callable[]
38
     */
39
    protected $filters = [];
40
41
    /**
42
     * Callables to sort the iterator
43
     *
44
     * @var callable[]
45
     */
46
    protected $sort_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
     * @inheritdoc
64
     */
65
    public function __set($property, $value)
66
    {
67
        throw new InvalidArgumentException(sprintf('%s is an undefined property', $property));
68
    }
69
70
    /**
71
     * @inheritdoc
72
     */
73
    public function __unset($property)
74
    {
75
        throw new InvalidArgumentException(sprintf('%s is an undefined property', $property));
76
    }
77
78
    /**
79
     * Returns a Record object
80
     *
81
     * @return RecordSet
82
     */
83
    public function process(AbstractCsv $csv)
84
    {
85
        $input_encoding = $csv->getInputEncoding();
86
        $use_converter = $this->useInternalConverter($csv);
87
        $header = $csv->getHeader();
88
        $header_offset = $csv->getHeaderOffset();
89
        $filters = [];
90
        if (null !== $header_offset) {
91
            $filters[] = function ($row, $index) use ($header_offset) {
92
                return $index !== $header_offset;
93
            };
94
        }
95
96
        $iterator = $this->formatIterator($csv, $header);
97
        $iterator = $this->convertIterator($iterator, $input_encoding, $use_converter);
98
        $iterator = $this->filter($iterator, $filters);
99
        $iterator = $this->uasort($iterator);
100
101
        return new RecordSet(new LimitIterator($iterator, $this->offset, $this->limit), $header);
102
    }
103
104
    /**
105
     * Remove the BOM sequence from the CSV
106
     *
107
     * @param AbstractCsv $csv
108
     *
109
     * @return Iterator
110
     */
111
    protected function applyBOMStripping(AbstractCsv $csv)
112
    {
113
        $bom = $csv->getInputBOM();
114
        if ('' === $bom) {
115
            return $csv->getIterator();
116
        }
117
118
        $enclosure = $csv->getEnclosure();
119
        $strip_bom = function ($row, $index) use ($bom, $enclosure) {
120
            if (0 != $index) {
121
                return $row;
122
            }
123
124
            return $this->stripBOM($row, $bom, $enclosure);
125
        };
126
127
        return new MapIterator($csv->getIterator(), $strip_bom);
128
    }
129
130
    /**
131
     * Apply CSV header to the return iterator
132
     *
133
     * @param AbstractCsv $csv
134
     *
135
     * @throws OutOfRangeException if the column is inconsistent
136
     *
137
     * @return Iterator
138
     */
139
    protected function formatIterator(AbstractCsv $csv, array $header)
140
    {
141
        $iterator = $this->applyBOMStripping($csv);
142
        if (empty($header)) {
143
            return $iterator;
144
        }
145
146
        $header_column_count = count($header);
147
        $combine_array = function (array $row) use ($header, $header_column_count) {
148
            if ($header_column_count != count($row)) {
149
                throw new OutOfRangeException('The record column count differs from the header column count');
150
            }
151
152
            return array_combine($header, $row);
153
        };
154
155
        return new MapIterator($iterator, $combine_array);
156
    }
157
158
    /**
159
    * Filter the Iterator
160
    *
161
    * @param Iterator $iterator
162
    *
163
    * @return Iterator
164
    */
165
    protected function filter(Iterator $iterator, array $filters)
166
    {
167
        $reducer = function ($iterator, $callable) {
168
            return new CallbackFilterIterator($iterator, $callable);
169
        };
170
171
        $filters[] = function ($row) {
172
            return is_array($row) && $row != [null];
173
        };
174
175
        return array_reduce(array_merge($filters, $this->filters), $reducer, $iterator);
176
    }
177
178
    /**
179
    * Sort the Iterator
180
    *
181
    * @param Iterator $iterator
182
    *
183
    * @return Iterator
184
    */
185
    protected function uasort(Iterator $iterator)
186
    {
187
        if (empty($this->sort_by)) {
188
            return $iterator;
189
        }
190
191
        $obj = new ArrayIterator(iterator_to_array($iterator));
192
        $obj->uasort(function ($row_a, $row_b) {
193
            $res = 0;
194
            foreach ($this->sort_by as $compare) {
195
                if (0 !== ($res = call_user_func($compare, $row_a, $row_b))) {
196
                    break;
197
                }
198
            }
199
200
            return $res;
201
        });
202
203
        return $obj;
204
    }
205
206
    /**
207
     * Convert Iterator to UTF-8 if needed
208
     *
209
     * @param Iterator $iterator
210
     * @param string   $input_encoding
211
     *
212
     * @return Iterator
213
     */
214
    protected function convertIterator(Iterator $iterator, $input_encoding, $use_converter)
215
    {
216
        if (!$use_converter) {
217
            return $iterator;
218
        }
219
220
        $convert_row = function ($row) use ($input_encoding) {
221
            return $this->convertRecord($row, $input_encoding);
222
        };
223
224
        return new MapIterator($iterator, $convert_row);
225
    }
226
227
    /**
228
     * Set LimitIterator Offset
229
     *
230
     * @param $offset
231
     *
232
     * @return static
233
     */
234
    public function setOffset($offset)
235
    {
236
        $offset = $this->validateInteger($offset, 0, 'the offset must be a positive integer or 0');
237
        if ($offset === $this->offset) {
238
            return $this;
239
        }
240
241
        $clone = clone $this;
242
        $clone->offset = $offset;
243
244
        return $clone;
245
    }
246
247
    /**
248
     * Set LimitIterator Count
249
     *
250
     * @param int $limit
251
     *
252
     * @return static
253
     */
254
    public function setLimit($limit)
255
    {
256
        $limit = $this->validateInteger($limit, -1, 'the limit must an integer greater or equals to -1');
257
        if ($limit === $this->limit) {
258
            return $this;
259
        }
260
261
        $clone = clone $this;
262
        $clone->limit = $limit;
263
264
        return $clone;
265
    }
266
267
    /**
268
     * Set an Iterator sorting callable function
269
     *
270
     * @param callable $callable
271
     *
272
     * @return static
273
     */
274
    public function addSortBy(callable $callable)
275
    {
276
        $clone = clone $this;
277
        $clone->sort_by[] = $callable;
278
279
        return $clone;
280
    }
281
282
    /**
283
     * Set the Iterator filter method
284
     *
285
     * @param callable $callable
286
     *
287
     * @return static
288
     */
289
    public function addFilter(callable $callable)
290
    {
291
        $clone = clone $this;
292
        $clone->filters[] = $callable;
293
294
        return $clone;
295
    }
296
}
297