Passed
Push — master ( b97c32...e7e450 )
by Carlos C
10:36 queued 12s
created

CsvFile::rewind()   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 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
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 106
    public function __construct(string $filename, ArrayProcessorInterface $rowProcessor = null)
25
    {
26 106
        if ('' === $filename) {
27 1
            throw new UnexpectedValueException('The filename cannot be empty');
28
        }
29 105
        if (is_dir($filename)) {
30 1
            throw new UnexpectedValueException('The filename is a directory');
31
        }
32 104
        $this->file = new SplFileObject($filename, 'r');
33 103
        $this->rowProcessor = (null === $rowProcessor) ? new NullArrayProcessor() : $rowProcessor;
34
    }
35
36 50
    public function position(): int
37
    {
38 50
        return $this->file->key();
39
    }
40
41 99
    public function move(int $position): void
42
    {
43 99
        $position = max(0, $position);
44 99
        if (0 === $position) {
45 2
            $this->file->rewind();
46 2
            return;
47
        }
48
49 98
        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 96
        $this->file->seek($position);
58
    }
59
60 58
    public function next(int $times = 1): void
61
    {
62 58
        if (1 === $times) {
63 53
            $this->file->next();
64 53
            return;
65
        }
66
67 5
        $this->move($this->position() + $times);
68
    }
69
70
    /** @return Generator<int, array<int, scalar>> */
71 9
    public function readLines(): Iterator
72
    {
73 9
        while (! $this->eof()) {
74 9
            yield $this->readLine();
75 9
            $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 98
    public function eof(): bool
85
    {
86 98
        if (! $this->file->valid()) {
87 1
            return true;
88
        }
89 97
        if ('' !== $this->file->current()) {
90 97
            return false;
91
        }
92
93
        // am I at the last empty line?
94 10
        $this->file->next();
95 10
        if ($this->file->valid()) {
96
            $this->previous();
97
            return false;
98
        }
99
100 10
        return true;
101
    }
102
103
    /** @return array<int, scalar> */
104 96
    public function readLine(): array
105
    {
106 96
        if ($this->eof()) {
107
            return [];
108
        }
109 96
        $contents = $this->file->current();
110 96
        $contents = (! is_string($contents)) ? '' : $contents;
111 96
        return $this->rowProcessor->execute(str_getcsv($contents));
112
    }
113
114
    /** @return array<int, scalar> */
115 3
    public function current(): array
116
    {
117 3
        return $this->readLine();
118
    }
119
120
    public function key(): int
121
    {
122
        return $this->file->key();
123
    }
124
125 1
    public function valid(): bool
126
    {
127 1
        return ! $this->eof();
128
    }
129
130 1
    public function rewind(): void
131
    {
132 1
        $this->file->rewind();
133
    }
134
135
    /**
136
     * @param int $offset
137
     */
138
    public function seek($offset): void
139
    {
140
        $this->move($offset);
141
    }
142
}
143