Passed
Push — master ( 3b7451...a0f654 )
by Fabrice
02:21
created

CsvExtractor::getTraversable()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 17
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 5
nop 1
dl 0
loc 17
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of YaEtl.
5
 *     (c) Fabrice de Stefanis / https://github.com/fab2s/YaEtl
6
 * This source file is licensed under the MIT license which you will
7
 * find in the LICENSE file or at https://opensource.org/licenses/MIT
8
 */
9
10
namespace fab2s\YaEtl\Loaders\File;
11
12
use fab2s\NodalFlow\NodalFlowException;
13
use fab2s\NodalFlow\YaEtlException;
14
use fab2s\YaEtl\Extractors\File\FileExtractorAbstract;
15
use fab2s\YaEtl\Traits\CsvHandlerTrait;
16
17
/**
18
 * Class CsvExtractor
19
 */
20
class CsvExtractor extends FileExtractorAbstract
21
{
22
    use CsvHandlerTrait;
23
24
    /**
25
     * CsvLoader constructor.
26
     *
27
     * @param resource|string $input
28
     * @param string|null     $delimiter
29
     * @param string|null     $enclosure
30
     * @param string|null     $escape
31
     *
32
     * @throws NodalFlowException
33
     * @throws YaEtlException
34
     */
35
    public function __construct($input, $delimiter = null, $enclosure = null, $escape = null)
36
    {
37
        parent::__construct($input);
38
        $this->initCsvOptions($delimiter, $enclosure, $escape);
39
    }
40
41
    /**
42
     * @param mixed $param
43
     *
44
     * @return \Generator
45
     */
46
    public function getTraversable($param = null)
47
    {
48
        if (!$this->extract($param)) {
49
            return;
50
        }
51
52
        if (false !== ($firstRecord = $this->getFirstRecord())) {
53
            /* @var array $firstRecord */
54
            yield $this->bakeRecord($firstRecord);
55
        }
56
57
        while (false !== ($record = fgetcsv($this->handle, 0, $this->delimiter, $this->enclosure, $this->escape))) {
58
            /* @var array $record */
59
            yield $this->bakeRecord($record);
60
        }
61
62
        $this->releaseHandle();
63
    }
64
65
    /**
66
     * @param array $record
67
     *
68
     * @return array
69
     */
70
    protected function bakeRecord(array $record)
71
    {
72
        return isset($this->header) ? array_combine($this->header, $record) : $record;
73
    }
74
75
    /**
76
     * @return string|bool
77
     */
78
    protected function getFirstRecord()
79
    {
80
        while (false !== ($line = fgets($this->handle))) {
81
            if ($line = trim($this->trimBom($line))) {
82
                $record = $this->handleHeader($line);
83
                if ($record === false) {
84
                    continue;
85
                }
86
87
                return $record;
88
            }
89
        }
90
91
        return false;
92
    }
93
94
    /**
95
     * @param string $line
96
     *
97
     * @return array|bool
98
     */
99
    protected function handleHeader($line)
100
    {
101
        // obey excel sep
102
        if (strpos($line, 'sep=') === 0) {
103
            $this->useSep    = true;
104
            $this->delimiter = $line[4];
105
106
            return false;
107
        }
108
109
        $record = str_getcsv($line, $this->delimiter, $this->enclosure, $this->escape);
110
        if ($this->useHeader && !isset($this->header)) {
111
            $this->header = array_map('trim', $record);
112
113
            return false;
114
        }
115
116
        return $record;
117
    }
118
119
    /**
120
     * @param array $record
121
     *
122
     * @return bool|int
123
     */
124
    protected function writeCsvLine(array $record)
125
    {
126
        return fputcsv($this->handle, $record, $this->delimiter, $this->enclosure, $this->escape);
127
    }
128
}
129