CsvTrait::readCsv()   A
last analyzed

Complexity

Conditions 4
Paths 19

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 12
c 2
b 1
f 0
dl 0
loc 18
rs 9.8666
cc 4
nc 19
nop 2
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * BEdita, API-first content management framework
6
 * Copyright 2023 Atlas Srl, Chialab Srl
7
 *
8
 * This file is part of BEdita: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published
10
 * by the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
14
 */
15
namespace BEdita\ImportTools\Utility;
16
17
use Cake\Core\InstanceConfigTrait;
18
use Generator;
19
20
/**
21
 * Trait for share Csv stuff.
22
 *
23
 * This provides `readCsv` method to progressively read a csv file line by line.
24
 *
25
 * Usage example:
26
 * ```php
27
 * use BEdita\ImportTools\Utility\CsvTrait;
28
 *
29
 * class MyImporter
30
 * {
31
 *     use CsvTrait;
32
 *
33
 *     public function import(string $filename): void
34
 *     {
35
 *         foreach ($this->readCsv($filename) as $obj) {
36
 *             // process $obj
37
 *         }
38
 *     }
39
 * }
40
 * ```
41
 */
42
trait CsvTrait
43
{
44
    use InstanceConfigTrait;
45
    use FileTrait;
46
47
    /**
48
     * Progressively read a CSV file, line by line
49
     *
50
     * @param string $path Path to CSV file
51
     * @param bool $assoc If `true` uses first CSV row as column names, thus yielding associative arrays. Otherwise, all rows are yielded and columns are indexed by their positions.
52
     * @return \Generator<array<array-key, string>>
53
     */
54
    protected function readCsv(string $path, bool $assoc = true): Generator
55
    {
56
        $delimiter = $this->getConfig('csv.delimiter', ',');
57
        $enclosure = $this->getConfig('csv.enclosure', '"');
58
        $escape = $this->getConfig('csv.escape', '\\');
59
60
        [$fh, $close] = static::readFileStream($path);
61
62
        try {
63
            flock($fh, LOCK_SH);
64
65
            $header = $assoc ? fgetcsv($fh, 0, $delimiter, $enclosure, $escape) : null;
66
            $i = 0;
67
            while (($row = fgetcsv($fh, 0, $delimiter, $enclosure, $escape)) !== false) {
68
                yield $i++ => $header !== null ? array_combine($header, $row) : $row;
69
            }
70
        } finally {
71
            $close();
72
        }
73
    }
74
}
75