Passed
Push — master ( c55c96...6ef54c )
by Claudson
06:47
created

Layout   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 14
eloc 45
c 3
b 0
f 0
dl 0
loc 105
ccs 44
cts 44
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A append() 0 10 3
A getContents() 0 3 1
A getTotalOfRecords() 0 3 1
A getStructure() 0 3 1
B parse() 0 41 7
A makeFileObject() 0 8 1
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 59
    public function append(Record $record, $occurrences = 1): self
32
    {
33 59
        if (! preg_match('/^([1-9][0-9]*)|(\*)$/', $occurrences)) {
34 5
            throw PediException::invalidQuantifier();
35
        }
36
37 54
        $occurrences = '*' === $occurrences ? $occurrences : (int) $occurrences;
38 54
        $this->structure[] = [$record, $occurrences];
39
40 54
        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 49
    public function getContents(): array
52
    {
53 49
        return $this->contents;
54
    }
55
56 50
    public function getTotalOfRecords(): int
57
    {
58 50
        return count($this->contents);
59
    }
60
61 50
    public function parse(string $fileContent)
62
    {
63 50
        $this->file = $this->makeFileObject($fileContent);
64 50
        $currentSection = 0;
65 50
        while ($this->file->valid()) {
66
            /** @var Record $baseRecord */
67 50
            [$baseRecord, $times] = $this->structure[$currentSection];
68
69
            do {
70 50
                $initialPosition = $this->file->ftell();
71 50
                $line = $this->file->getCurrentLine();
72 50
                $endOfCurrentLine = $this->file->ftell();
73
74
                // When the line doesn't match the expected record, unread and go to next section
75 50
                if ('*' === $times && ! $baseRecord->matches($line)) {
76 21
                    $this->file->fseek($initialPosition);
77 21
                    $moreRecordsExists = false;
78
                }
79
                else {
80
                    /** @var Record $item */
81 50
                    $item = unserialize(serialize($baseRecord));
82 50
                    $item->setLineNumber($this->file->key() + 1);
83 50
                    $item->parse($line);
84 50
                    $this->contents[] = $item;
85
86 50
                    if ('*' === $times) {
87
                        try {
88 46
                            $nextLine = $this->file->getCurrentLine();
89 1
                        } catch (\RuntimeException $exception) {
90 1
                            break;
91
                        }
92 46
                        $this->file->fseek($endOfCurrentLine);
93 46
                        $moreRecordsExists = $baseRecord->matches($nextLine);
94
                    } else {
95 49
                        $times--;
96 49
                        $moreRecordsExists = $times > 0;
97
                    }
98
                }
99 50
            } while ($moreRecordsExists);
100
101 50
            $currentSection++;
102
        }
103 50
    }
104
105 50
    private function makeFileObject(string $fileContent): SplTempFileObject
106
    {
107 50
        $file = new SplTempFileObject();
108 50
        $file->setFlags(SplTempFileObject::DROP_NEW_LINE);
109 50
        $file->fwrite($fileContent);
110 50
        $file->rewind();
111
112 50
        return $file;
113
    }
114
}
115