324 lines
12 KiB
PHP
324 lines
12 KiB
PHP
<?php
|
|
|
|
if (!isset($baseDir)) {
|
|
$baseDir = $_SERVER['DOCUMENT_ROOT'];
|
|
}
|
|
|
|
//ini_set('display_errors', 1);
|
|
//ini_set('display_startup_errors', 1);
|
|
|
|
require $baseDir . '/../composer/vendor/autoload.php';
|
|
|
|
use ChrisKonnertz\StringCalc\StringCalc;
|
|
|
|
class NotenRechner {
|
|
|
|
private $Rfunctions = ["MAXR", "MINR", "AVGR", "SUMR"];
|
|
private $RfunctionsSan = [];
|
|
|
|
public function __construct(
|
|
private StringCalc $rechner = new StringCalc()
|
|
) {
|
|
$this->RfunctionsSan = implode('|', array_map('preg_quote', $this->Rfunctions));
|
|
}
|
|
|
|
/*
|
|
Es wird ein Array mit allen Notentypen pro Gerät, Jahr und Person erwartet, so dass noten_bezeichnung_id als Key verwendet werden kann:
|
|
|
|
$valuesArray = [
|
|
noten_bezeichnung_id => value,
|
|
…
|
|
];
|
|
*/
|
|
|
|
private function santinzeString(string $string) : string
|
|
{
|
|
$replacePatterns = [
|
|
'/->R\w+/', // 1. Removes ->R followed by digits
|
|
'/[^a-zA-Z0-9(){}+*\/.[\]\-]/' // 2. Fixed syntax: Allowed characters list
|
|
];
|
|
return preg_replace($replacePatterns,'', $string);
|
|
}
|
|
|
|
private function sanitizeStringWithRun(string $string) : string
|
|
{
|
|
$replacePattern = '/[^a-zA-Z0-9(){}+*\/.\-\[\]>]/';
|
|
return preg_replace($replacePattern, "", $string);
|
|
}
|
|
|
|
|
|
public function getBenoetigteIds(string $schemaRaw)
|
|
{
|
|
$schema = $this->santinzeString($schemaRaw);
|
|
|
|
preg_match_all('/\{(\d+)\}/', $schema, $matches);
|
|
return $matches[1];
|
|
|
|
}
|
|
|
|
public function getBenoetigteIdsComplex(string $schemaRaw)
|
|
{
|
|
$schema = $this->santinzeString($schemaRaw);
|
|
$indexedMatches = [];
|
|
|
|
// Pattern breakdown:
|
|
// \{(\d+) -> Match { and capture the first number (Note ID)
|
|
// (?:\[(\w*)\])? -> OPTIONALLY match [ and capture alphanumeric content inside (Apparatus ID)
|
|
// (?:\[(\d+)\])? -> OPTIONALLY match [ and capture number inside (Run Number)
|
|
// \} -> Match the closing }
|
|
if (preg_match_all('/\{(\d+)(?:\[(\w*)\])?(?:\[(\d+)\])?\}/', $schema, $matches, PREG_SET_ORDER)) {
|
|
|
|
foreach ($matches as $match) {
|
|
$noteId = $match[1];
|
|
|
|
$rawGeraet = $match[2] ?? 'S';
|
|
$geraetId = ($rawGeraet === 'S' || $rawGeraet === '') ? 'A' : $rawGeraet;
|
|
|
|
$runNumber = isset($match[3]) ? (int)$match[3] : 1;
|
|
|
|
$indexedMatches[] = [
|
|
'noteId' => $noteId,
|
|
'geraetId' => $geraetId,
|
|
'run' => $runNumber
|
|
];
|
|
}
|
|
}
|
|
|
|
return $indexedMatches;
|
|
|
|
}
|
|
|
|
public function getBenoetigteIdsComplexWithRun(string $schemaRaw)
|
|
{
|
|
$schema = $this->sanitizeStringWithRun($schemaRaw);
|
|
$indexedMatches = [];
|
|
|
|
// Pattern breakdown:
|
|
// \{(\d+) -> Match { and capture the first number (Note ID)
|
|
// (?:\[(\w*)\])? -> OPTIONALLY match [ and capture alphanumeric content inside (Apparatus ID)
|
|
// (?:\[(\d+)\])? -> OPTIONALLY match [ and capture number inside (Run Number)
|
|
// \} -> Match the closing }
|
|
if (preg_match_all('/\{(\d+)(?:\[(\w*)\])?(?:\[(\d+)\])?\}/', $schema, $matches, PREG_SET_ORDER)) {
|
|
|
|
foreach ($matches as $match) {
|
|
$noteId = $match[1];
|
|
|
|
$rawGeraet = $match[2] ?? 'S';
|
|
$geraetId = ($rawGeraet === 'S' || $rawGeraet === '') ? 'A' : $rawGeraet;
|
|
|
|
$runNumber = isset($match[3]) ? (int)$match[3] : 1;
|
|
|
|
$indexedMatches[] = [
|
|
'noteId' => $noteId,
|
|
'geraetId' => $geraetId,
|
|
'run' => $runNumber
|
|
];
|
|
}
|
|
}
|
|
|
|
$arrayRes = $this->getStoreGeraetRun($schemaRaw);
|
|
|
|
$indexedMatches['targetRun'] = $arrayRes['run_num'] ?? 'A';
|
|
$indexedMatches['targetGeraet'] = $arrayRes['geraet_id'] ?? 'A';
|
|
|
|
return $indexedMatches;
|
|
|
|
}
|
|
|
|
public function getStoreGeraetRun(string $schemaRaw): array
|
|
{
|
|
$schema = $this->sanitizeStringWithRun($schemaRaw);
|
|
|
|
$pattern = '/->R(?<run_num>\d+|S)(?:G(?<geraet_id>\d+|S))?/';
|
|
|
|
if (preg_match($pattern, $schema, $matchesTagetRun)) {
|
|
|
|
$run = $matchesTagetRun['run_num'] ?? 'S';
|
|
$geraet = $matchesTagetRun['geraet_id'] ?? 'S';
|
|
|
|
return [
|
|
'run_num' => $run === 'S' ? 'A' : (int)$run,
|
|
'geraet_id' => $geraet === 'S' ? 'A' : (int)$geraet,
|
|
];
|
|
}
|
|
|
|
return [
|
|
'run_num' => 'A',
|
|
'geraet_id' => 'A'
|
|
];
|
|
}
|
|
|
|
private function insertValuesComplex(string $schemaRaw, array $valuesArray, int $currentId, int $runNumber, bool $avr = false)
|
|
{
|
|
$schema = $this->santinzeString($schemaRaw);
|
|
$idsNeededArray = $this->getBenoetigteIdsComplex($schemaRaw);
|
|
|
|
// 1. Validation Loop
|
|
foreach ($idsNeededArray as $sina) {
|
|
$noteId = $sina['noteId'];
|
|
$geraetIdSearch = ($sina['geraetId'] === 'A') ? $currentId : $sina['geraetId'];
|
|
|
|
if (!isset($valuesArray[$geraetIdSearch][$noteId][$runNumber]["value"])) {
|
|
return ['success' => false, 'value' => "Fehlende Daten für Gerät $geraetIdSearch, Note $noteId, Lauf $runNumber"];
|
|
}
|
|
}
|
|
|
|
try {
|
|
$returnStr = preg_replace_callback('/\{(\d+)(?:\[(\w*)\])?(?:\[(\d+)\])?\}/', function($m) use ($valuesArray, $currentId, $runNumber, $avr) {
|
|
$noteId = $m[1];
|
|
|
|
// Get value inside brackets, default to 'S' if none exists
|
|
$rawGeraet = $m[2] ?? 'S';
|
|
$geraetId = ($rawGeraet === 'S' || $rawGeraet === '') ? $currentId : $rawGeraet;
|
|
|
|
if ($avr && $valuesArray[$geraetId][$noteId][$runNumber]["type"] === 'default_value') {
|
|
return 'default_value_skip';
|
|
} else {
|
|
// Return value from [Device][Note][Run]
|
|
return $valuesArray[$geraetId][$noteId][$runNumber]["value"] ?? 0;
|
|
}
|
|
|
|
}, $schema);
|
|
|
|
return ['success' => true, 'value' => $returnStr];
|
|
|
|
} catch (\Exception $e) {
|
|
return ['success' => false, 'value' => 'Problem beim Einsetzen der Werte'];
|
|
}
|
|
}
|
|
|
|
private function calculate(string $rechnungRaw) {
|
|
global $rechner;
|
|
|
|
$rechnung = $this->santinzeString($rechnungRaw);
|
|
|
|
try {
|
|
$result = $this->rechner->calculate($rechnung);
|
|
return ['success' => true, 'value' => floatval($result)];
|
|
} catch (\ChrisKonnertz\StringCalc\Exceptions\StringCalcException $e) {
|
|
return ['success' => false, 'value' => 'Problem bei der Berechnung: Ungültige Syntax '. $rechnung];
|
|
} catch (\Exception $e) {
|
|
return ['success' => false, 'value' => 'Problem bei der Berechnung'];
|
|
}
|
|
}
|
|
|
|
public function berechneStringComplex(string $schemaRaw, array $valuesArray = [], int $geraetId = -1, int $run_number = 0) {
|
|
if ($schemaRaw === '') { return ['success' => false, 'value' => 'Leeres Schema']; }
|
|
if ($geraetId < 0) { return ['success' => false, 'value' => 'Keine Geraet Id angegeben.']; }
|
|
if ($run_number === 0) { return ['success' => false, 'value' => 'Keine Run_Number angegeben.']; }
|
|
|
|
$rechnungArray = $this->insertValuesComplex($schemaRaw, $valuesArray, $geraetId, $run_number);
|
|
|
|
if (!isset($rechnungArray['success']) || !isset($rechnungArray['value']) || !$rechnungArray['success']) {
|
|
return ['success' => false, 'value' => $rechnungArray['value'] . " RECHNUNG: " . $schemaRaw ?? 'Fehler beim Einsetzen der Werte oder Werte fehlen'];
|
|
}
|
|
|
|
return $this->calculate($rechnungArray['value']);
|
|
}
|
|
|
|
public function berechneStringComplexRun(string $schemaRaw, array $valuesArray = [], int $geraetId = -1, int $programm = 0, array $arrayRuns = []) {
|
|
if ($schemaRaw === '') { return ['success' => false, 'value' => 'Leeres Schema']; }
|
|
if ($geraetId < 0) { return ['success' => false, 'value' => 'Keine Geraet Id angegeben.']; }
|
|
if ($programm === 0) { return ['success' => false, 'value' => 'Kein Programm angegeben.']; }
|
|
if ($arrayRuns === []) { return ['success' => false, 'value' => 'Leeres Array Runs Noten.']; }
|
|
|
|
$rechnung = $this->insertRunValues($schemaRaw, $valuesArray, $geraetId, $programm, $arrayRuns);
|
|
|
|
if (!isset($rechnung) || $rechnung === '') {
|
|
return ['success' => false, 'value' => 'Fehler beim Einsetzen der Werte oder Werte fehlen'];
|
|
}
|
|
|
|
return $this->calculate($rechnung);
|
|
}
|
|
|
|
private function insertRunValues($schema, $valuesArray, $currentId, $programm, $arrayRuns) {
|
|
$pattern = '/(?P<fn_name>' . $this->RfunctionsSan . ')\((?P<content>(?:(?R)|[^()])*)\)/';
|
|
|
|
return preg_replace_callback($pattern, function($m) use ($valuesArray, $currentId, $programm, $arrayRuns) {
|
|
$name = $m['fn_name'];
|
|
$content = $m['content'];
|
|
|
|
// Resolve inner nested functions first
|
|
$content = $this->insertRunValues($content, $valuesArray, $currentId, $programm, $arrayRuns);
|
|
|
|
if (!in_array($name, $this->Rfunctions)) {
|
|
return $m[0];
|
|
}
|
|
|
|
$parts = [];
|
|
|
|
$ids = $this->getBenoetigteIdsComplex($content);
|
|
|
|
$runCount = 0;
|
|
|
|
foreach ($ids as $sid) {
|
|
$geraetId = ($sid['geraetId'] === 'A') ? $currentId : $sid['geraetId'];
|
|
$runCountN = $arrayRuns[$sid['noteId']][$geraetId][$programm] ?? $arrayRuns[$sid['noteId']][$geraetId]["all"] ?? $arrayRuns["default"] ?? 1;
|
|
|
|
if ($runCount !== $runCountN && $runCount !== 0) { return; }
|
|
$runCount = $runCountN;
|
|
}
|
|
|
|
$string = "";
|
|
switch ($name) {
|
|
case "AVGR":
|
|
case "SUMR":
|
|
$nulls = 0;
|
|
|
|
for ($r = 1; $r <= $runCount; $r++) {
|
|
|
|
$res = $this->insertValuesComplex($content, $valuesArray, $currentId, $r, true);
|
|
|
|
if (!$res['success']) {
|
|
return "0";
|
|
} elseif ($res['value'] === 'default_value_skip') {
|
|
$nulls++;
|
|
} else {
|
|
$parts[] = "(" . $res['value'] . ")";
|
|
}
|
|
}
|
|
|
|
$innerMath = implode(" + ", $parts);
|
|
$div_count = $runCount - $nulls;
|
|
if ($div_count === 0 || count($parts) < 1) return "0";
|
|
$string = ($name === "AVGR") ? "(($innerMath) / $div_count)" : "($innerMath)";
|
|
|
|
break;
|
|
|
|
case "MAXR":
|
|
case "MINR":
|
|
$arrayRunValues = [];
|
|
for ($r = 1; $r <= $runCount; $r++) {
|
|
$res = $this->berechneStringComplex($content, $valuesArray, $currentId, $r);
|
|
|
|
// FIXED: Access the ['value'] key of the returned array
|
|
if ($res['success']) {
|
|
$arrayRunValues[] = floatval($res['value']);
|
|
} else {
|
|
$arrayRunValues[] = 0;
|
|
}
|
|
}
|
|
// Safety check for empty arrays to prevent max() errors
|
|
if (empty($arrayRunValues)) return "0";
|
|
|
|
$string = ($name === "MAXR") ? max($arrayRunValues) : min($arrayRunValues);
|
|
break;
|
|
}
|
|
|
|
return (string)$string;
|
|
}, $schema);
|
|
}
|
|
|
|
public function checkRunFunctions(string $schemaRaw) {
|
|
|
|
if ($schemaRaw === '') {
|
|
return ['success' => false, 'value' => 'Leeres Schema'];
|
|
}
|
|
|
|
$schema = $this->santinzeString($schemaRaw);
|
|
|
|
$pattern = '/(?P<fn_name>' . $this->RfunctionsSan . ')\((?:(?R)|[^()])*+\)/';
|
|
|
|
return (bool) preg_match($pattern, $schema);
|
|
}
|
|
} |