first commit
This commit is contained in:
100
app/Services/FormulaService.php
Normal file
100
app/Services/FormulaService.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?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'],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user