Completed
Push — master ( a94b15...b2eb2c )
by ignace nyamagana
03:05
created

AbstractCsv::getConversionIterator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 5
Bugs 2 Features 0
Metric Value
c 5
b 2
f 0
dl 0
loc 10
ccs 7
cts 7
cp 1
rs 9.4286
cc 1
eloc 7
nc 1
nop 0
crap 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.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
namespace League\Csv;
14
15
use InvalidArgumentException;
16
use Iterator;
17
use IteratorAggregate;
18
use JsonSerializable;
19
use League\Csv\Config\Controls;
20
use League\Csv\Config\Output;
21
use League\Csv\Modifier\QueryFilter;
22
use League\Csv\Modifier\StreamFilter;
23
use SplFileInfo;
24
use SplFileObject;
25
use SplTempFileObject;
26
27
/**
28
 *  An abstract class to enable basic CSV manipulation
29
 *
30
 * @package League.csv
31
 * @since  4.0.0
32
 *
33
 */
34
abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
35
{
36
    use Controls;
37
38
    use Output;
39
40
    use QueryFilter;
41
42
    use StreamFilter;
43
44
    /**
45
     *  UTF-8 BOM sequence
46
     */
47
    const BOM_UTF8 = "\xEF\xBB\xBF";
48
49
    /**
50
     * UTF-16 BE BOM sequence
51
     */
52
    const BOM_UTF16_BE = "\xFE\xFF";
53
54
    /**
55
     * UTF-16 LE BOM sequence
56
     */
57
    const BOM_UTF16_LE = "\xFF\xFE";
58
59
    /**
60
     * UTF-32 BE BOM sequence
61
     */
62
    const BOM_UTF32_BE = "\x00\x00\xFE\xFF";
63
64
    /**
65
     * UTF-32 LE BOM sequence
66
     */
67
    const BOM_UTF32_LE = "\x00\x00\xFF\xFE";
68
69
    /**
70
     * return an array
71
     */
72
    const TYPE_ARRAY = 1;
73
74
    /**
75
     * return an iterator
76
     */
77
    const TYPE_ITERATOR = 2;
78
79
    /**
80
     * The constructor path
81
     *
82
     * can be a SplFileInfo object or the string path to a file
83
     *
84
     * @var SplFileObject|string
85
     */
86
    protected $path;
87
88
    /**
89
     * The file open mode flag
90
     *
91
     * @var string
92
     */
93
    protected $open_mode;
94
95
    /**
96
     * Creates a new instance
97
     *
98
     * The path must be an SplFileInfo object
99
     * an object that implements the `__toString` method
100
     * a path to a file
101
     *
102
     * @param SplFileObject|string $path      The file path
103
     * @param string               $open_mode The file open mode flag
104
     */
105 234
    protected function __construct($path, $open_mode = 'r+')
106
    {
107 234
        $this->open_mode = strtolower($open_mode);
108 234
        $this->path = $path;
109 234
        $this->initStreamFilter($this->path);
110 234
    }
111
112
    /**
113
     * The destructor
114
     */
115 160
    public function __destruct()
116
    {
117 160
        $this->path = null;
118 160
    }
119
120
    /**
121
     * Returns the inner SplFileObject
122
     *
123
     * @return SplFileObject
124
     */
125 174
    public function getIterator()
126
    {
127 174
        $this->returnType = self::TYPE_ARRAY;
128 174
        $iterator = $this->path;
129 174
        if (!$iterator instanceof SplFileObject) {
130 22
            $iterator = new SplFileObject($this->getStreamFilterPath(), $this->open_mode);
131 22
        }
132 174
        $iterator->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
133 174
        $iterator->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY);
134
135 174
        return $iterator;
136
    }
137
138
    /**
139
     * Returns the CSV Iterator
140
     *
141
     * @return Iterator
142
     */
143
    protected function getCsvIterator()
144
    {
145 112
        $this->addFilter(function ($row) {
146 108
            return is_array($row) && $row != [null];
147 112
        });
148 112
        $iterator = $this->getIterator();
149 112
        $iterator = $this->applyBomStripping($iterator);
150 112
        $iterator = $this->applyIteratorFilter($iterator);
151 112
        $iterator = $this->applyIteratorSortBy($iterator);
152
153 112
        return $this->applyIteratorInterval($iterator);
154
    }
155
156
    /**
157
     * Creates a {@link AbstractCsv} from a string
158
     *
159
     * The path can be:
160
     * - an SplFileInfo,
161
     * - a SplFileObject,
162
     * - an object that implements the `__toString` method,
163
     * - a string
164
     *
165
     * BUT NOT a SplTempFileObject
166
     *
167
     * <code>
168
     *<?php
169
     * $csv = new Reader::createFromPath('/path/to/file.csv', 'a+');
170
     * $csv = new Reader::createFromPath(new SplFileInfo('/path/to/file.csv'));
171
     * $csv = new Reader::createFromPath(new SplFileObject('/path/to/file.csv'), 'rb');
172
     *
173
     * ?>
174
     * </code>
175
     *
176
     * @param mixed  $path      file path
177
     * @param string $open_mode the file open mode flag
178
     *
179
     * @throws InvalidArgumentException If $path is a SplTempFileObject object
180
     *
181
     * @return static
182
     */
183 36
    public static function createFromPath($path, $open_mode = 'r+')
184
    {
185 36
        if ($path instanceof SplTempFileObject) {
186 2
            throw new InvalidArgumentException('an `SplTempFileObject` object does not contain a valid path');
187
        }
188
189 34
        if ($path instanceof SplFileInfo) {
190 2
            $path = $path->getPath().'/'.$path->getBasename();
191 2
        }
192
193 34
        return new static(static::validateString($path), $open_mode);
194
    }
195
196
    /**
197
     * validate a string
198
     *
199
     * @param mixed $str the value to evaluate as a string
200
     *
201
     * @throws InvalidArgumentException if the submitted data can not be converted to string
202
     *
203
     * @return string
204
     */
205 60
    protected static function validateString($str)
206
    {
207 60
        if (is_string($str) || (is_object($str) && method_exists($str, '__toString'))) {
208 58
            return (string) $str;
209
        }
210 2
        throw new InvalidArgumentException('Expected data must be a string or stringable');
211
    }
212
213
    /**
214
     * Creates a {@link AbstractCsv} from a SplFileObject
215
     *
216
     * The path can be:
217
     * - a SplFileObject,
218
     * - a SplTempFileObject
219
     *
220
     * <code>
221
     *<?php
222
     * $csv = new Writer::createFromFileObject(new SplFileInfo('/path/to/file.csv'));
223
     * $csv = new Writer::createFromFileObject(new SplTempFileObject);
224
     *
225
     * ?>
226
     * </code>
227
     *
228
     * @param SplFileObject $file
229
     *
230
     * @return static
231
     */
232 206
    public static function createFromFileObject(SplFileObject $file)
233
    {
234 206
        return new static($file);
235
    }
236
237
    /**
238
     * Creates a {@link AbstractCsv} from a string
239
     *
240
     * The string must be an object that implements the `__toString` method,
241
     * or a string
242
     *
243
     * @param string|object $str the string
244
     *
245
     * @return static
246
     */
247 18
    public static function createFromString($str)
248
    {
249 18
        $file = new SplTempFileObject();
250 18
        $file->fwrite(static::validateString($str));
251
252 18
        return static::createFromFileObject($file);
253
    }
254
255
    /**
256
     * Creates a {@link AbstractCsv} instance from another {@link AbstractCsv} object
257
     *
258
     * @param string $class     the class to be instantiated
259
     * @param string $open_mode the file open mode flag
260
     *
261
     * @return static
262
     */
263 4
    protected function newInstance($class, $open_mode)
264
    {
265 4
        $csv = new $class($this->path, $open_mode);
266 4
        $csv->delimiter = $this->delimiter;
267 4
        $csv->enclosure = $this->enclosure;
268 4
        $csv->escape = $this->escape;
269 4
        $csv->encodingFrom = $this->encodingFrom;
270 4
        $csv->input_bom = $this->input_bom;
271 4
        $csv->output_bom = $this->output_bom;
272 4
        $csv->newline = $this->newline;
273
274 4
        return $csv;
275
    }
276
277
    /**
278
     * Creates a {@link Writer} instance from a {@link AbstractCsv} object
279
     *
280
     * @param string $open_mode the file open mode flag
281
     *
282
     * @return Writer
283
     */
284 2
    public function newWriter($open_mode = 'r+')
285
    {
286 2
        return $this->newInstance(Writer::class, $open_mode);
287
    }
288
289
    /**
290
     * Creates a {@link Reader} instance from a {@link AbstractCsv} object
291
     *
292
     * @param string $open_mode the file open mode flag
293
     *
294
     * @return Reader
295
     */
296 2
    public function newReader($open_mode = 'r+')
297
    {
298 2
        return $this->newInstance(Reader::class, $open_mode);
299
    }
300
301
    /**
302
     * Validate the submitted integer
303
     *
304
     * @param int    $int
305
     * @param int    $minValue
306
     * @param string $errorMessage
307
     *
308
     * @throws InvalidArgumentException If the value is invalid
309
     *
310
     * @return int
311
     */
312 72
    protected function filterInteger($int, $minValue, $errorMessage)
313
    {
314 72
        if (false === ($int = filter_var($int, FILTER_VALIDATE_INT, ['options' => ['min_range' => $minValue]]))) {
315 12
            throw new InvalidArgumentException($errorMessage);
316
        }
317 62
        return $int;
318
    }
319
}
320