Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
78.72% |
74 / 94 |
|
88.24% |
15 / 17 |
CRAP | |
0.00% |
0 / 1 |
File | |
78.72% |
74 / 94 |
|
88.24% |
15 / 17 |
41.86 | |
0.00% |
0 / 1 |
get | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
fromString | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
determineType | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
__construct | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
2 | |||
readFileMeta | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
load | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
4 | |||
validate | |
50.00% |
1 / 2 |
|
0.00% |
0 / 1 |
2.50 | |||
getType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getVersion | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getVersionMayorMinor | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isValid | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
report | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
4 | |||
crossValidate | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
addRelation | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
jsonSerialize | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
6 | |||
getContent | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | declare(strict_types=1); |
3 | |
4 | class File extends FileData { |
5 | private const type = 'file'; |
6 | public const canBeRelationSubject = false; |
7 | public const canBeRelationObject = false; |
8 | protected string $name = ''; |
9 | protected ?string $content = null; |
10 | |
11 | static function get(string|FileData $init, string $type = null): File { |
12 | if (!$type and !is_a($init, FileData::class)) { |
13 | $type = File::determineType($init); |
14 | } |
15 | |
16 | return match ($type) { |
17 | 'Testtakers' => new XMLFileTesttakers($init), |
18 | 'SysCheck' => new XMLFileSysCheck($init), |
19 | 'Booklet' => new XMLFileBooklet($init), |
20 | 'Unit' => new XMLFileUnit($init), |
21 | 'Resource' => new ResourceFile($init), |
22 | 'xml' => new XMLFile($init), |
23 | default => new File($init), |
24 | }; |
25 | } |
26 | |
27 | /** For use in testing classes */ |
28 | static function fromString(string $fileContent, string $fileName = 'virtual_file'): File { |
29 | $file = new static(new FileData($fileName)); |
30 | $file->content = $fileContent; |
31 | $file->validate(); |
32 | return $file; |
33 | } |
34 | |
35 | // TODO unit-test |
36 | public static function determineType(string $path): string { |
37 | if (strtoupper(substr($path, -4)) == '.XML') { |
38 | $asGenericXmlFile = new XMLFile($path); |
39 | if (!in_array($asGenericXmlFile->rootTagName, XMLFile::knownRootTags)) { |
40 | return 'xml'; |
41 | } |
42 | return $asGenericXmlFile->rootTagName; |
43 | } else { |
44 | return 'Resource'; |
45 | } |
46 | } |
47 | |
48 | public function __construct(string|FileData $init) { |
49 | if (is_a($init, FileData::class)) { |
50 | $this->path = $init->path; |
51 | $this->type = $init->type; |
52 | $this->id = $init->id; |
53 | $this->label = $init->label; |
54 | $this->description = $init->description; |
55 | $this->validationReport = $init->validationReport; |
56 | $this->relations = $init->relations; |
57 | $this->modificationTime = $init->modificationTime; |
58 | $this->size = $init->size; |
59 | $this->name = basename($init->path); |
60 | $this->contextData = $init->contextData; |
61 | $this->veronaModuleType = $init->veronaModuleType; |
62 | $this->veronaModuleId = $init->veronaModuleId; |
63 | $this->versionMayor = $init->versionMayor; |
64 | $this->versionMinor = $init->versionMinor; |
65 | $this->versionPatch = $init->versionPatch; |
66 | $this->versionLabel = $init->versionLabel; |
67 | $this->veronaVersion = $init->veronaVersion; |
68 | return; |
69 | } |
70 | |
71 | parent::__construct(); |
72 | |
73 | $this->readFileMeta($init); |
74 | $this->id = strtoupper($this->getName()); |
75 | |
76 | $this->load(); |
77 | } |
78 | |
79 | public function readFileMeta(string $path): void { // TODO can this be private / merged with load? |
80 | |
81 | $this->path = $path; |
82 | |
83 | if (!file_exists($path)) { |
84 | $this->size = 0; |
85 | $this->name = basename($path); |
86 | $this->modificationTime = 1; |
87 | $this->report('error', "File does not exist: `" . dirname($path) . '/'. basename($path) . "`"); |
88 | |
89 | } else { |
90 | $this->size = filesize($path); |
91 | $this->name = basename($path); |
92 | $this->modificationTime = FileTime::modification($path); |
93 | } |
94 | } |
95 | |
96 | protected function load(): void { |
97 | if (($this->content === null) and $this->path and file_exists($this->path)) { |
98 | $this->content = file_get_contents($this->path); |
99 | $this->validate(); |
100 | } |
101 | } |
102 | |
103 | protected function validate(): void { |
104 | if (strlen($this->name) > 120) { |
105 | $this->report('error', "Filename too long!"); |
106 | } |
107 | } |
108 | |
109 | public function getType(): string { |
110 | return $this->type ?? $this::type; |
111 | } |
112 | |
113 | public function getName(): string { |
114 | return $this->name; |
115 | } |
116 | |
117 | public function getVersion(): string { |
118 | return Version::asString($this->versionMayor, $this->versionMinor, $this->versionPatch, $this->versionLabel) ?? ''; |
119 | } |
120 | |
121 | public function getVersionMayorMinor(): string { |
122 | return "$this->versionMayor.$this->versionMinor"; |
123 | } |
124 | |
125 | public function isValid(): bool { |
126 | return count($this->validationReport['error'] ?? []) == 0; |
127 | } |
128 | |
129 | public function report(string $level, string $message): void { |
130 | if (isset($this->validationReport[$level]) and count($this->validationReport[$level]) == 5) { |
131 | $aggregated = str_ends_with($this->validationReport[$level][4], " more {$level}s.") ? (int) $this->validationReport[$level][4] : 1; |
132 | $this->validationReport[$level][4] = ($aggregated + 1) . " more {$level}s."; |
133 | } else { |
134 | $this->validationReport[$level][] = $message; |
135 | } |
136 | } |
137 | |
138 | // TODO unit-test |
139 | public function crossValidate(WorkspaceCache $workspaceCache): void { |
140 | if ($duplicateId = $workspaceCache->getDuplicateId($this)) { |
141 | $origFile = $workspaceCache->getFile($this->getType(), $this->getId()); |
142 | |
143 | $this->report('error', "Duplicate {$this->getType()}-Id: `{$this->getId()}` ({$origFile->getName()})"); |
144 | $this->id = $duplicateId; |
145 | } |
146 | } |
147 | |
148 | public function addRelation(FileRelation $relation): void { |
149 | $this->relations[] = $relation; |
150 | } |
151 | |
152 | public function jsonSerialize(): mixed { |
153 | $info = [ |
154 | 'label' => $this->getLabel(), |
155 | 'description' => $this->getDescription(), |
156 | ]; |
157 | if ($this->veronaModuleType) { |
158 | $info['veronaModuleType'] = $this->veronaModuleType; |
159 | $info['veronaVersion'] = $this->veronaVersion; |
160 | $info['version'] = $this->getVersion(); |
161 | } |
162 | |
163 | return [ |
164 | 'name' => $this->name, |
165 | 'size' => $this->size, |
166 | 'modificationTime' => $this->modificationTime, |
167 | 'type' => $this->type, |
168 | 'id' => $this->id, |
169 | 'report' => $this->validationReport, |
170 | 'dependencies' => $this->relations, |
171 | 'info' => array_merge($info, $this->getContextData() |
172 | ), |
173 | ]; |
174 | } |
175 | |
176 | public function getContent(): string { |
177 | $this->load(); |
178 | return $this->content; |
179 | } |
180 | } |
181 |