Completed
Push — master ( afa401...19e2a9 )
by Andy
02:13
created

Reader::getOpenMode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
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 bool */
27
    private $bom = false;
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
     * @param NormalizerInterface $headerNormalizer
87
     *
88
     * @return self
89
     */
90
    public function setHeaderNormalizer(NormalizerInterface $headerNormalizer)
91
    {
92
        $this->headerNormalizer = $headerNormalizer;
93
94
        return $this;
95
    }
96
97
    /**
98
     * @param mixed               $key
99
     * @param NormalizerInterface $normalizer Normalizer instance.
100
     *
101
     * @return self
102
     */
103
    public function addNormalizer($key, NormalizerInterface $normalizer)
104
    {
105
        $this->normalizers[$key] = $normalizer;
106
107
        return $this;
108
    }
109
110
    /**
111
     * @param array|\Traversable $normalizers
112
     *
113
     * @return self
114
     */
115
    public function addNormalizers($normalizers)
116
    {
117
        foreach ($normalizers as $key => $normalizer) {
118
            $this->addNormalizer($key, $normalizer);
119
        }
120
121
        return $this;
122
    }
123
124
    /**
125
     * @param mixed $key
126
     *
127
     * @return NormalizerInterface
128
     */
129 8
    public function getNormalizer($key)
130
    {
131 8
        if ($this->hasHeaders && \is_int($key)) {
132 4
            $this->normalizers[$key] = $this->headerNormalizer;
133
        }
134
135 8
        if (!isset($this->normalizers[$key])) {
136 6
            $class = $this->getDefaultNormalizer();
137
138 6
            $this->normalizers[$key] = new $class();
139
        }
140
141 8
        return $this->normalizers[$key];
142
    }
143
144
    /**
145
     * Reads the next line in the CSV file
146
     * and returns a Row object from it.
147
     *
148
     * @return Row|null
149
     */
150 5
    protected function getCurrentRow()
151
    {
152 5
        $cells = $this->getDocument()->current();
153
154 5
        if (!\is_array($cells) || $cells == [null]) {
155 3
            return null;
156
        }
157
158 5
        if ($this->key() === 0 && $this->hasBom()) {
159 1
            $stripped = StringUtil::stripBom($cells[0], StringUtil::BOM_UTF8);
160
161 1
            if ($stripped !== $cells[0]) {
162 1
                $cells[0] = \trim($stripped, $this->getEnclosure());
163
            }
164
        }
165
166 5
        $row = new Row($cells, $this);
167
168 5
        return $row;
169
    }
170
171
    /**
172
     * @inheritDoc
173
     */
174 3
    public function current()
175
    {
176 3
        return $this->row;
177
    }
178
179
    /**
180
     * @inheritDoc
181
     */
182 3
    public function next()
183
    {
184 3
        $this->getDocument()->next();
185 3
    }
186
187
    /**
188
     * @inheritDoc
189
     */
190 5
    public function key()
191
    {
192 5
        return $this->getDocument()->key();
193
    }
194
195
    /**
196
     * @inheritDoc
197
     */
198 3
    public function valid()
199
    {
200 3
        $this->row = $this->getCurrentRow();
201
202 3
        return $this->row instanceof Row;
203
    }
204
205
    /**
206
     * @inheritDoc
207
     */
208 5
    public function rewind()
209
    {
210 5
        $this->getDocument()->rewind();
211
212 5
        $dataOffset = $this->offset + $this->headerOffset;
213 5
        if ($this->hasHeaders()) {
214 4
            if ($this->headerOffset) {
215 1
                $this->getDocument()->seek($this->headerOffset);
216
            }
217
218
            // Set headers to null first so the header row is a zero-based array and can be used
219
            // to set the array keys of all other rows.
220 4
            $this->headers = null;
221 4
            $this->headers = $this->getCurrentRow();
222
223 4
            ++$dataOffset;
224
        }
225
226 5
        if ($dataOffset) {
227 4
            $this->getDocument()->seek($dataOffset);
228
        }
229 5
    }
230
231
    /**
232
     * @param string $defaultNormalizer
233
     *
234
     * @return Reader
235
     */
236
    public function setDefaultNormalizer($defaultNormalizer)
237
    {
238
        $this->defaultNormalizer = $defaultNormalizer;
239
240
        return $this;
241
    }
242
243
    /**
244
     * @return string
245
     */
246 6
    public function getDefaultNormalizer()
247
    {
248 6
        return $this->defaultNormalizer;
249
    }
250
251
    /**
252
     * @param bool $bom
253
     *
254
     * @return Reader
255
     */
256 2
    public function setBom($bom)
257
    {
258 2
        $this->bom = $bom;
259
260 2
        return $this;
261
    }
262
263
    /**
264
     * @return bool
265
     */
266 4
    public function hasBom()
267
    {
268 4
        return $this->bom;
269
    }
270
271
    /**
272
     * @param int $offset
273
     *
274
     * @return self
275
     */
276 1
    public function setOffset($offset)
277
    {
278 1
        $this->offset = $offset;
279
280 1
        return $this;
281
    }
282
283
    /**
284
     * @return int
285
     */
286
    public function getOffset()
287
    {
288
        return $this->offset;
289
    }
290
291
    /**
292
     * @param int $headerOffset
293
     *
294
     * @return self
295
     */
296 1
    public function setHeaderOffset($headerOffset)
297
    {
298 1
        $this->headerOffset = $headerOffset;
299
300 1
        return $this;
301
    }
302
303
    /**
304
     * @return int
305
     */
306
    public function getHeaderOffset()
307
    {
308
        return $this->headerOffset;
309
    }
310
311
    /**
312
     * @return array
313
     */
314 1
    public function toArray()
315
    {
316 1
        $result = [];
317 1
        foreach ($this as $rowKey => $row) {
318 1
            $result[$rowKey] = $row->toArray();
319
        }
320
321 1
        return $result;
322
    }
323
}
324