Passed
Push — master ( 0e87cd...c4ac3e )
by Carlos C
12:45 queued 01:03
created

CsvFile::move()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10
c 1
b 0
f 0
dl 0
loc 17
ccs 11
cts 11
cp 1
rs 9.9332
cc 3
nc 3
nop 1
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpCfdi\SatCatalogosPopulate\Utils;
6
7
use Generator;
8
use Iterator;
9
use PhpCfdi\SatCatalogosPopulate\Utils\ArrayProcessors\ArrayProcessorInterface;
10
use PhpCfdi\SatCatalogosPopulate\Utils\ArrayProcessors\NullArrayProcessor;
11
use SeekableIterator;
12
use SplFileObject;
13
use UnexpectedValueException;
14
15
/**
16
 * @implements SeekableIterator<int, array<int, scalar>>
17
 */
18
class CsvFile implements SeekableIterator
19
{
20
    private SplFileObject $file;
21
22
    private ArrayProcessorInterface $rowProcessor;
23
24 207
    public function __construct(string $filename, ArrayProcessorInterface $rowProcessor = null)
25
    {
26 207
        if ('' === $filename) {
27 1
            throw new UnexpectedValueException('The filename cannot be empty');
28
        }
29 206
        if (is_dir($filename)) {
30 1
            throw new UnexpectedValueException('The filename is a directory');
31
        }
32 205
        $this->file = new SplFileObject($filename, 'r');
33 204
        $this->rowProcessor = $rowProcessor ?? new NullArrayProcessor();
34
    }
35
36 100
    public function position(): int
37
    {
38 100
        return $this->file->key();
39
    }
40
41 200
    public function move(int $position): void
42
    {
43 200
        $position = max(0, $position);
44 200
        if (0 === $position) {
45 2
            $this->file->rewind();
46 2
            return;
47
        }
48
49 199
        if (1 === $position) {
50
            // this is a bugfix, otherwise it doesn't go to line 1
51 2
            $this->file->rewind();
52 2
            $this->current();
53 2
            $this->file->next();
54 2
            return;
55
        }
56
57 197
        $this->file->seek($position);
58
    }
59
60 109
    public function next(int $times = 1): void
61
    {
62 109
        if (1 === $times) {
63 104
            $this->file->next();
64 104
            return;
65
        }
66
67 5
        $this->move($this->position() + $times);
68
    }
69
70
    /** @return Generator<int, array<int, scalar>> */
71 10
    public function readLines(): Iterator
72
    {
73 10
        while (! $this->eof()) {
74 10
            yield $this->readLine();
75 10
            $this->next();
76
        }
77
    }
78
79 3
    public function previous(int $times = 1): void
80
    {
81 3
        $this->move($this->position() - $times);
82
    }
83
84 199
    public function eof(): bool
85
    {
86 199
        if (! $this->file->valid()) {
87 1
            return true;
88
        }
89 198
        if ('' !== $this->file->current()) {
90 198
            return false;
91
        }
92
93
        // am I at the last empty line?
94 11
        $this->file->next();
95 11
        if ($this->file->valid()) {
96
            $this->previous();
97
            return false;
98
        }
99
100 11
        return true;
101
    }
102
103
    /** @return array<int, scalar> */
104 197
    public function readLine(): array
105
    {
106 197
        if ($this->eof()) {
107
            return [];
108
        }
109 197
        $contents = $this->file->current();
110 197
        $contents = (! is_string($contents)) ? '' : $contents;
111 197
        $values = array_map(
112 197
            fn ($value) => (is_scalar($value)) ? $value : '',
113 197
            str_getcsv($contents)
114
        );
115 197
        return $this->rowProcessor->execute($values);
116
    }
117
118
    /** @return array<int, scalar> */
119 3
    public function current(): array
120
    {
121 3
        return $this->readLine();
122
    }
123
124
    public function key(): int
125
    {
126
        return $this->file->key();
127
    }
128
129 1
    public function valid(): bool
130
    {
131 1
        return ! $this->eof();
132
    }
133
134 1
    public function rewind(): void
135
    {
136 1
        $this->file->rewind();
137
    }
138
139
    public function seek(int $offset): void
140
    {
141
        $this->move($offset);
142
    }
143
}
144