Passed
Push — master ( 08379c...c55c96 )
by Claudson
07:14
created

Layout::parse()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 33
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 23
dl 0
loc 33
ccs 21
cts 21
cp 1
c 1
b 0
f 0
rs 9.2408
cc 5
nc 4
nop 1
crap 5
1
<?php
2
3
namespace Claudsonm\Pedi\Structure;
4
5
use Claudsonm\Pedi\Exceptions\PediException;
6
use SplTempFileObject;
7
8
class Layout
9
{
10
    /**
11
     * @var array|Record[]
12
     */
13
    protected array $contents = [];
14
15
    /**
16
     * Defines the records and their occurrences within the layout.
17
     */
18
    protected array $structure = [];
19
20
    private SplTempFileObject $file;
21
22
    /**
23
     * Adds a record definition to the end of the layout structure.
24
     *
25
     * @param int|string $occurrences the amount of sequential items expected for the given record
26
     *
27
     * @throws PediException
28
     *
29
     * @return $this
30
     */
31 58
    public function append(Record $record, $occurrences = 1): self
32
    {
33 58
        if (! preg_match('/^([1-9][0-9]*)|(\*)$/', $occurrences)) {
34 5
            throw PediException::invalidQuantifier();
35
        }
36
37 53
        $occurrences = '*' === $occurrences ? $occurrences : (int) $occurrences;
38 53
        $this->structure[] = [$record, $occurrences];
39
40 53
        return $this;
41
    }
42
43 4
    public function getStructure(): array
44
    {
45 4
        return $this->structure;
46
    }
47
48
    /**
49
     * @return array|Record[]
50
     */
51 48
    public function getContents(): array
52
    {
53 48
        return $this->contents;
54
    }
55
56 49
    public function getTotalOfRecords(): int
57
    {
58 49
        return count($this->contents);
59
    }
60
61 49
    public function parse(string $fileContent)
62
    {
63 49
        $this->file = $this->makeFileObject($fileContent);
64 49
        $currentSection = 0;
65 49
        while ($this->file->valid()) {
66
            /** @var Record $baseRecord */
67 49
            [$baseRecord, $times] = $this->structure[$currentSection];
68
69
            do {
70 49
                $line = $this->file->getCurrentLine();
71 49
                $endOfCurrentLine = $this->file->ftell();
72
73
                /** @var Record $item */
74 49
                $item = unserialize(serialize($baseRecord));
75 49
                $item->setLineNumber($this->file->key() + 1);
76 49
                $item->parse($line);
77 49
                $this->contents[] = $item;
78
79 49
                if ('*' === $times) {
80
                    try {
81 45
                        $nextLine = $this->file->getCurrentLine();
82 1
                    } catch (\RuntimeException $exception) {
83 1
                        break;
84
                    }
85 45
                    $this->file->fseek($endOfCurrentLine);
86 45
                    $moreRecordsExists = $baseRecord->matches($nextLine);
87
                } else {
88 48
                    $times--;
89 48
                    $moreRecordsExists = $times > 0;
90
                }
91 49
            } while ($moreRecordsExists);
92
93 49
            $currentSection++;
94
        }
95 49
    }
96
97 49
    private function makeFileObject(string $fileContent): SplTempFileObject
98
    {
99 49
        $file = new SplTempFileObject();
100 49
        $file->setFlags(SplTempFileObject::DROP_NEW_LINE);
101 49
        $file->fwrite($fileContent);
102 49
        $file->rewind();
103
104 49
        return $file;
105
    }
106
}
107