Completed
Push — master ( 1cc7be...c5c5ef )
by Andy
04:04
created

Reader::setBom()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Palmtree\Csv;
4
5
use Palmtree\Csv\Normalizer\NormalizerInterface;
6
use Palmtree\Csv\Normalizer\NullNormalizer;
7
use Palmtree\Csv\Row\Row;
8
use Palmtree\Csv\Util\StringUtil;
9
10
/**
11
 * Reads a CSV file by loading each line into memory
12
 * one at a time.
13
 */
14
class Reader extends AbstractCsv implements \Iterator
15
{
16
    /** @var string */
17
    private $defaultNormalizer = NullNormalizer::class;
18
    /** @var NormalizerInterface */
19
    private $headerNormalizer;
20
    /** @var NormalizerInterface[] */
21
    private $normalizers = [];
22
    /** @var Row */
23
    private $headers;
24
    /** @var Row */
25
    private $row;
26
    /** @var string|null */
27
    private $stripBom = StringUtil::BOM_UTF8;
28
    /** @var int */
29
    private $offset = 0;
30
    /** @var int */
31
    private $headerOffset = 0;
32
33 9
    public function __construct($file, $hasHeaders = true, $delimiter = ',', $enclosure = '"', $escape = "\0")
34
    {
35 9
        $this->headerNormalizer = new NullNormalizer();
36 9
        parent::__construct($file, $hasHeaders, $delimiter, $enclosure, $escape);
37 9
    }
38
39
    /**
40
     * @return string
41
     */
42 6
    public function getOpenMode()
43
    {
44 6
        return 'r';
45
    }
46
47
    /**
48
     * @param string $file
49
     *
50
     * @return Reader
51
     */
52
    public static function read($file)
53
    {
54
        $csv = new static($file);
55
56
        return $csv;
57
    }
58
59
    /**
60
     * @return Row
61
     */
62 3
    public function getHeaders()
63
    {
64 3
        if (null === $this->headers && $this->hasHeaders()) {
65 3
            $this->rewind();
66
        }
67
68 3
        return $this->headers;
69
    }
70
71
    /**
72
     * @param $key
73
     *
74
     * @return mixed
75
     */
76 8
    public function getHeader($key)
77
    {
78 8
        if (!isset($this->headers[$key])) {
79 8
            return $key;
80
        }
81
82 2
        return $this->headers[$key];
83
    }
84
85
    /**
86
     * @return self
87
     */
88
    public function setHeaderNormalizer(NormalizerInterface $headerNormalizer)
89
    {
90
        $this->headerNormalizer = $headerNormalizer;
91
92
        return $this;
93
    }
94
95
    /**
96
     * @param mixed               $key
97
     * @param NormalizerInterface $normalizer Normalizer instance.
98
     *
99
     * @return self
100
     */
101
    public function addNormalizer($key, NormalizerInterface $normalizer)
102
    {
103
        $this->normalizers[$key] = $normalizer;
104
105
        return $this;
106
    }
107
108
    /**
109
     * @param array|\Traversable $normalizers
110
     *
111
     * @return self
112
     */
113
    public function addNormalizers($normalizers)
114
    {
115
        foreach ($normalizers as $key => $normalizer) {
116
            $this->addNormalizer($key, $normalizer);
117
        }
118
119
        return $this;
120
    }
121
122
    /**
123
     * @param mixed $key
124
     *
125
     * @return NormalizerInterface
126
     */
127 8
    public function getNormalizer($key)
128
    {
129 8
        if ($this->hasHeaders && \is_int($key)) {
130 4
            $this->normalizers[$key] = $this->headerNormalizer;
131
        }
132
133 8
        if (!isset($this->normalizers[$key])) {
134 6
            $class = $this->getDefaultNormalizer();
135
136 6
            $this->normalizers[$key] = new $class();
137
        }
138
139 8
        return $this->normalizers[$key];
140
    }
141
142
    /**
143
     * Reads the next line in the CSV file and returns a Row object from it.
144
     *
145
     * @return Row|null
146
     */
147 5
    protected function getCurrentRow()
148
    {
149 5
        $cells = $this->getDocument()->current();
150
151 5
        if (!\is_array($cells) || $cells == [null]) {
152 3
            return null;
153
        }
154
155 5
        if ($this->key() === 0 && $this->stripBom !== null) {
156 4
            $stripped = StringUtil::stripBom($cells[0], $this->stripBom);
157
158 4
            if ($stripped !== $cells[0]) {
159 1
                $cells[0] = \trim($stripped, $this->getEnclosure());
160
            }
161
        }
162
163 5
        return new Row($cells, $this);
164
    }
165
166
    /**
167
     * @inheritDoc
168
     */
169 3
    public function current()
170
    {
171 3
        return $this->row;
172
    }
173
174
    /**
175
     * @inheritDoc
176
     */
177 3
    public function next()
178
    {
179 3
        $this->getDocument()->next();
180 3
    }
181
182
    /**
183
     * @inheritDoc
184
     */
185 5
    public function key()
186
    {
187 5
        return $this->getDocument()->key();
188
    }
189
190
    /**
191
     * @inheritDoc
192
     */
193 3
    public function valid()
194
    {
195 3
        $this->row = $this->getCurrentRow();
196
197 3
        return $this->row instanceof Row;
198
    }
199
200
    /**
201
     * @inheritDoc
202
     */
203 5
    public function rewind()
204
    {
205 5
        $this->getDocument()->rewind();
206
207 5
        $dataOffset = $this->offset + $this->headerOffset;
208 5
        if ($this->hasHeaders()) {
209 4
            if ($this->headerOffset) {
210 1
                $this->getDocument()->seek($this->headerOffset);
211
            }
212
213
            // Set headers to null first so the header row is a zero-based array and can be used
214
            // to set the array keys of all other rows.
215 4
            $this->headers = null;
216 4
            $this->headers = $this->getCurrentRow();
217
218 4
            ++$dataOffset;
219
        }
220
221 5
        if ($dataOffset) {
222 4
            $this->getDocument()->seek($dataOffset);
223
        }
224 5
    }
225
226
    /**
227
     * @param string $defaultNormalizer
228
     *
229
     * @return Reader
230
     */
231
    public function setDefaultNormalizer($defaultNormalizer)
232
    {
233
        $this->defaultNormalizer = $defaultNormalizer;
234
235
        return $this;
236
    }
237
238
    /**
239
     * @return string
240
     */
241 6
    public function getDefaultNormalizer()
242
    {
243 6
        return $this->defaultNormalizer;
244
    }
245
246
    /**
247
     * @param string|null $stripBom
248
     *
249
     * @return Reader
250
     */
251 1
    public function setStripBom($stripBom)
252
    {
253 1
        $this->stripBom = $stripBom;
254
255 1
        return $this;
256
    }
257
258
    /**
259
     * @param int $offset
260
     *
261
     * @return self
262
     */
263 1
    public function setOffset($offset)
264
    {
265 1
        $this->offset = $offset;
266
267 1
        return $this;
268
    }
269
270
    /**
271
     * @return int
272
     */
273
    public function getOffset()
274
    {
275
        return $this->offset;
276
    }
277
278
    /**
279
     * @param int $headerOffset
280
     *
281
     * @return self
282
     */
283 1
    public function setHeaderOffset($headerOffset)
284
    {
285 1
        $this->headerOffset = $headerOffset;
286
287 1
        return $this;
288
    }
289
290
    /**
291
     * @return int
292
     */
293
    public function getHeaderOffset()
294
    {
295
        return $this->headerOffset;
296
    }
297
298
    /**
299
     * @return array
300
     */
301 1
    public function toArray()
302
    {
303 1
        $result = [];
304 1
        foreach ($this as $rowKey => $row) {
305 1
            $result[$rowKey] = $row->toArray();
306
        }
307
308 1
        return $result;
309
    }
310
}
311