Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.00% covered (warning)
88.00%
44 / 50
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
XMLSchema
88.00% covered (warning)
88.00%
44 / 50
20.00% covered (danger)
20.00%
1 / 5
25.00
0.00% covered (danger)
0.00%
0 / 1
 parseSchemaUrl
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
10
 getLocalSchema
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
2.01
 getSchemaFilePath
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
4.13
 accessDefinitionsDir
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 accessSchemaCache
78.57% covered (warning)
78.57%
11 / 14
0.00% covered (danger)
0.00%
0 / 1
6.35
1<?php
2/** @noinspection PhpUnhandledExceptionInspection */
3declare(strict_types=1);
4
5class XMLSchema {
6  // TODO use defined class instead of plain array
7  static function parseSchemaUrl(string $schemaUri): ?array {
8    $regex = '#^(http)?.*?((\d+).(\d+).(\d+)(-\S*)?)?/definitions/v?o?_?(\S*).xsd$#';
9    preg_match_all($regex, $schemaUri, $matches, PREG_SET_ORDER);
10
11    if (!count($matches)) {
12      return null;
13    }
14
15    $urlParts = $matches[0];
16
17    $schemaData = [
18      "isExternal" => ($urlParts[1] === 'http') && isset($urlParts[2]),
19      "version" => $urlParts[2] ?? '',
20      "mayor" => isset($urlParts[3]) ? (int) $urlParts[3] : 0,
21      "minor" => isset($urlParts[4]) ? (int) $urlParts[4] : 0,
22      "patch" => isset($urlParts[5]) ? (int) $urlParts[5] : 0,
23      "label" => isset($urlParts[6]) ? substr($urlParts[6], 1) : '',
24      "type" => $urlParts[7] ?? '',
25      "uri" => $schemaUri
26    ];
27
28    if ($schemaData['version'] and $schemaData['type'] and ($schemaData['version'] === SystemConfig::$system_version)) {
29      return XMLSchema::getLocalSchema($schemaData['type']);
30    }
31
32    return $schemaData;
33  }
34
35  static function getLocalSchema(string $type): array {
36    if (!file_exists(ROOT_DIR . "/definitions/vo_$type.xsd")) {
37      throw new Exception("Unknown XML type: `$type`");
38    }
39
40    $currentVersion = SystemConfig::$system_version;
41    $schemaData = Version::split($currentVersion);
42    $schemaData["version"] = $currentVersion;
43    $schemaData["isExternal"] = false;
44    $schemaData["type"] = $type;
45    $schemaData["uri"] = false;
46
47    return $schemaData;
48  }
49
50  static function getSchemaFilePath(?array $schemaData): string {
51    if (!$schemaData) {
52      return '';
53    }
54
55    if (!SystemConfig::$debug_allowExternalXmlSchema or !$schemaData['isExternal']) {
56      return XMLSchema::accessDefinitionsDir($schemaData);
57    } else {
58      return XMLSchema::accessSchemaCache($schemaData);
59    }
60  }
61
62  private static function accessDefinitionsDir($schemaData): string {
63    $filePath = ROOT_DIR . "/definitions/vo_{$schemaData['type']}.xsd";
64
65    if (file_exists($filePath)) {
66      return $filePath;
67    }
68
69    return "";
70  }
71
72  private static function accessSchemaCache(array $schemaData): string {
73    if (!$schemaData['isExternal']) {
74      return '';
75    }
76
77    $folder = DATA_DIR . "/.schemas/{$schemaData['type']}/v{$schemaData['mayor']}/";
78    $fileName = "{$schemaData['type']}-{$schemaData['version']}.xsd";
79
80    if (file_exists("$folder$fileName")) {
81      if (!filesize("$folder$fileName")) {
82        return "";
83      }
84
85      return "$folder$fileName";
86    }
87
88    Folder::createPath($folder);
89
90    if (!is_writable($folder)) {
91      throw new Exception("`$folder` is not writeable!");
92    }
93
94    $fileContent = ExternalFile::download($schemaData['uri']);
95
96    file_put_contents("$folder$fileName", $fileContent);
97
98    return $fileContent ? "$folder$fileName" : '';
99  }
100}