Files
onboard/app/Infrastructure/Reports/Repositories/EloquentReportRepository.php

114 lines
4.7 KiB
PHP

<?php
namespace App\Infrastructure\Reports\Repositories;
use App\Domain\Reports\Contracts\ReportRepository;
use App\Domain\Reports\Models\ReportSnapshot;
use App\Domain\Reports\Models\SavedReportResult;
use App\Infrastructure\Reports\Adapters\LegacyReportServiceAdapter;
use App\Models\MetrikaResult;
use App\Models\ObservationPatient;
use App\Models\Report;
use App\Models\UnwantedEvent;
use App\Infrastructure\Reports\Services\ReportMetricsFinalizer;
use App\Infrastructure\Reports\Services\ReportStorageService;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use RuntimeException;
class EloquentReportRepository implements ReportRepository
{
public function __construct(
private readonly LegacyReportServiceAdapter $legacyAdapter,
?ReportStorageService $reportStorageService = null,
?ReportMetricsFinalizer $reportMetricsFinalizer = null,
) {
$this->reportStorageService = $reportStorageService ?? app(ReportStorageService::class);
$this->reportMetricsFinalizer = $reportMetricsFinalizer ?? app(ReportMetricsFinalizer::class);
}
private readonly ReportStorageService $reportStorageService;
private readonly ReportMetricsFinalizer $reportMetricsFinalizer;
public function save(ReportSnapshot $snapshot): SavedReportResult
{
$this->legacyAdapter->prepareMemoryForHeavySave();
$actor = $snapshot->actorUserId ? User::query()->find($snapshot->actorUserId) : null;
if (! $actor) {
throw new RuntimeException('Actor user was not found.');
}
$report = DB::transaction(function () use ($snapshot, $actor) {
$report = $this->reportStorageService->createOrUpdateReport($snapshot, $actor);
$this->reportStorageService->saveMetrics($report, $snapshot);
$this->reportStorageService->saveUnwantedEvents($report, $snapshot);
$this->reportStorageService->saveObservationPatients($report, $snapshot);
$this->legacyAdapter->createPatientSnapshots($report, $actor, $snapshot, $snapshot->autoFill);
$this->legacyAdapter->syncCalculatedMetrics($report, $actor, $snapshot);
return $report;
});
DB::transaction(function () use ($report) {
$this->reportMetricsFinalizer->finalize($report);
$this->legacyAdapter->saveLethalMetricFromSnapshots($report);
});
$this->legacyAdapter->clearCacheAfterReportCreation($actor, $report);
$savedSnapshot = $this->findSnapshot((int) $report->report_id);
if (! $savedSnapshot) {
throw new RuntimeException('Saved report could not be reloaded for comparison.');
}
return new SavedReportResult(
reportId: (int) $report->report_id,
snapshot: $savedSnapshot,
);
}
public function findSnapshot(int $reportId): ?ReportSnapshot
{
/** @var Report|null $report */
$report = Report::query()
->with(['metrikaResults', 'observationPatients', 'unwantedEvents'])
->find($reportId);
if (! $report || ! $report->period_start || ! $report->period_end) {
return null;
}
return new ReportSnapshot(
departmentId: (int) $report->rf_department_id,
userId: (int) ($report->rf_lpudoctor_id ?? $report->rf_user_id),
actorUserId: (int) $report->rf_user_id,
periodStart: new \DateTimeImmutable($report->period_start->format('Y-m-d H:i:s')),
periodEnd: new \DateTimeImmutable($report->period_end->format('Y-m-d H:i:s')),
status: (string) ($report->status ?? 'draft'),
autoFill: false,
metrics: $report->metrikaResults
->mapWithKeys(fn (MetrikaResult $metric) => [(int) $metric->rf_metrika_item_id => $metric->value])
->all(),
observationPatients: $report->observationPatients
->map(fn (ObservationPatient $patient) => [
'medical_history_id' => $patient->rf_medicalhistory_id,
'department_patient_id' => $patient->rf_department_patient_id,
'comment' => $patient->comment,
])->values()->all(),
unwantedEvents: $report->unwantedEvents
->map(fn (UnwantedEvent $event) => [
'title' => $event->title,
'comment' => $event->comment,
'is_visible' => (bool) $event->is_visible,
])->values()->all(),
reportId: (int) $report->report_id,
createdAt: $report->created_at ? new \DateTimeImmutable($report->created_at->format('Y-m-d H:i:s')) : null,
sentAt: $report->sent_at ? new \DateTimeImmutable($report->sent_at->format('Y-m-d H:i:s')) : null,
);
}
}