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 { $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; } private function insertValues(string $schemaRaw, array $valuesArray = []) { $schema = $this->santinzeString($schemaRaw); $idsNeeded = $this->getBenoetigteIds($schemaRaw); $missingIds = array_diff($idsNeeded, array_keys($valuesArray)); if (!empty($missingIds)) { return ['success' => false, 'value' => 'Fehlende IDs']; } try { $returnStr = preg_replace_callback('/\{(\d+)\}/', function($m) use ($valuesArray) { return $valuesArray[$m[1]]; }, $schema); return ['success' => true, 'value' => $returnStr]; } catch (\Exception $e) { return ['success' => false, 'value' => 'Problem beim Einsetzen der Werte']; } } private function insertValuesComplex(string $schemaRaw, array $valuesArray, int $currentId, int $runNumber) { $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])) { 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) { $noteId = $m[1]; // Get value inside brackets, default to 'S' if none exists $rawGeraet = $m[2] ?? 'S'; $geraetId = ($rawGeraet === 'S' || $rawGeraet === '') ? $currentId : $rawGeraet; // Return value from [Device][Note][Run] return $valuesArray[$geraetId][$noteId][$runNumber] ?? 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']; } catch (\Exception $e) { return ['success' => false, 'value' => 'Problem bei der Berechnung']; } } public function berechneString(string $schemaRaw, array $valuesArray = []) { if ($schemaRaw === '') { return ['success' => false, 'value' => 'Leeres Schema']; } $rechnungArray = $this->insertValues($schemaRaw, $valuesArray); if (!isset($rechnungArray['success']) || !isset($rechnungArray['value']) || !$rechnungArray['success']) { return ['success' => false, 'value' => $rechnungArray['value'] ?? 'Fehler beim Einsetzen der Werte oder Werte fehlen']; } return $this->calculate($rechnungArray['value']); } public function berechneStringComplex(string $schemaRaw, array $valuesArray = [], int $geraetId = 0, 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 = 0, 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' . $this->RfunctionsSan . ')\((?P(?:(?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["default"] ?? 1; //var_dump($arrayRuns[$sid['noteId']][$geraetId][$programm]); if ($runCount !== $runCountN && $runCount !== 0) { return; } $runCount = $runCountN; } $string = ""; switch ($name) { case "AVGR": case "SUMR": for ($r = 1; $r <= $runCount; $r++) { $res = $this->insertValuesComplex($content, $valuesArray, $currentId, $r); // FIXED: Only bail if success is false if (!$res['success']) { return "0"; // Or handle error as needed } $parts[] = "(" . $res['value'] . ")"; } $innerMath = implode(" + ", $parts); $string = ($name === "AVGR") ? "(($innerMath) / $runCount)" : "($innerMath)"; //var_dump($string); 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' . $this->RfunctionsSan . ')\((?:(?R)|[^()])*+\)/'; return (bool) preg_match($pattern, $schema); } }