Files
KarbonDatacenter/app/Services/FormulaService.php
2026-06-24 20:32:14 +08:00

101 lines
3.2 KiB
PHP

<?php
namespace App\Services;
use App\Models\ChecklistTemplate;
use App\Models\Submission;
/**
* Mengira hasil formula seksyen (A, B, C, D, E ...) berdasarkan jawapan serahan.
*
* Token tersedia kepada formula:
* - formula_token bagi setiap checklist_item (cth: SKOP1, EE, RE, D4I)
* - result_token bagi setiap formula yang telah dikira sebelumnya (cth: A, B)
*
* Formula dinilai mengikut turutan `order` supaya C boleh merujuk A & B, dsb.
*/
class FormulaService
{
public function __construct(protected ExpressionEvaluator $evaluator) {}
/**
* Kira semua hasil formula bagi satu serahan.
*
* @return array<int, array{result_token:string,label:?string,value:?float,unit:?string}>
*/
public function computeForSubmission(Submission $submission): array
{
$template = $submission->checklistTemplate
?: ($submission->checklist_template_id ? ChecklistTemplate::find($submission->checklist_template_id) : ChecklistTemplate::activeTemplate());
if (! $template) {
return [];
}
// Bina peta token => nilai daripada jawapan item.
$variables = [];
$answers = $submission->relationLoaded('answers')
? $submission->answers
: $submission->answers()->with('item')->get();
foreach ($answers as $answer) {
$item = $answer->item;
if ($item && $item->formula_token) {
$variables[$item->formula_token] = is_numeric($answer->value) ? (float) $answer->value : 0.0;
}
}
return $this->compute($template, $variables);
}
/**
* Kira hasil formula daripada peta pemboleh ubah mentah (berguna untuk ujian).
*
* @param array<string, float|int|null> $variables
* @return array<int, array{result_token:string,label:?string,value:?float,unit:?string}>
*/
public function compute(ChecklistTemplate $template, array $variables): array
{
$formulas = $template->relationLoaded('formulas')
? $template->formulas->sortBy('order')
: $template->formulas()->orderBy('order')->get();
$results = [];
foreach ($formulas as $formula) {
$value = $this->evaluator->evaluate($formula->expression, $variables, $formula->guard_div_zero);
// Hasil ini menjadi token yang boleh dirujuk oleh formula seterusnya.
$variables[$formula->result_token] = $value ?? 0.0;
$results[] = [
'result_token' => $formula->result_token,
'label' => $formula->label,
'value' => $value,
'unit' => $formula->unit,
];
}
return $results;
}
/**
* Kira semula dan simpan hasil ke dalam jadual submission_results.
*/
public function recalculateAndStore(Submission $submission): void
{
$results = $this->computeForSubmission($submission);
foreach ($results as $r) {
$submission->results()->updateOrCreate(
['result_token' => $r['result_token']],
[
'label' => $r['label'],
'value' => $r['value'],
'unit' => $r['unit'],
]
);
}
}
}