Files
healthcareapi/app/Services/DiseaseRecordService.php
T
2026-06-08 19:58:50 +07:00

482 lines
17 KiB
PHP

<?php
namespace App\Services;
use App\Models\Disease;
use App\Models\DiseaseRecord;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;
use App\Services\LogActionService;
class DiseaseRecordService
{
protected $diseaseService;
protected $fileStorage;
private const DEFAULT_PER_PAGE = 10;
private const MAX_PER_PAGE = 100;
public function __construct(
DiseaseService $diseaseService,
FileStorageService $fileStorage)
{
$this->diseaseService = $diseaseService;
$this->fileStorage = $fileStorage;
}
public function createDiseaseRecord(array $data, $userId): array
{
try {
DB::beginTransaction();
$diseaseId = $data['diseaseId'];
unset($data['diseaseId']);
[$schema, $message] = $this->diseaseService->getSchemaField($diseaseId);
foreach ($data['data'] as $key => $value) {
$fieldSchema = collect($schema)->firstWhere('name', $key);
if (!$fieldSchema) {
throw new \Exception("Field '{$key}' is not defined in the schema.");
}
if ($fieldSchema['type'] === 'file') {
$isMultiple = $fieldSchema['multiple'] ?? false;
if ($isMultiple) {
$value = is_array($value) ? $value : [$value];
$fileUrls = [];
foreach ($value as $index => $file) {
if ($file && is_file($file)) {
$fileUrls[] = $this->fileStorage->storeRecordFile(
$file,
$diseaseId,
$key . '-' . ($index + 1)
);
}
}
$data['data'][$key] = $fileUrls;
} else if (is_file($value)){
$data['data'][$key] = $this->fileStorage->storeRecordFile($value, $diseaseId, $key);
}
} else {
// Process non-file fields normally
$data['data'][$key] = $value;
}
}
$diseaseRecord = DiseaseRecord::create([
'disease_id' => $diseaseId,
'data' => $data['data'],
]);
DB::commit();
LogActionService::logAction(
$userId,
'create',
'DiseaseRecord',
$diseaseRecord->id,
$diseaseRecord->toArray(),
"Created disease record for disease ID: {$diseaseId}",
true
);
return [true, 'Disease record created successfully.', $diseaseRecord->toArray()];
} catch (\Throwable $exception) {
DB::rollBack();
LogActionService::logAction(
$userId,
'create',
'DiseaseRecord',
null,
[
'disease_id' => $diseaseId ?? null,
'error' => $exception->getMessage()
],
"Failed to create disease record: {$exception->getMessage()}",
false
);
return [false, 'Disease record creation failed: ' . $exception->getMessage(), []];
}
}
public function editDiseaseRecord($recordId, array $data, $userId): array
{
try {
DB::beginTransaction();
$diseaseRecord = DiseaseRecord::find($recordId);
if (!$diseaseRecord) {
DB::rollBack();
LogActionService::logAction(
$userId,
'delete',
'Disease',
$recordId,
['error' => 'Disease Record not found'],
"Failed to delete disease record: Disease Record not found",
false
);
return [false, 'Disease Record not found.', []];
}
$oldData = $diseaseRecord->toArray();
$existingData = $diseaseRecord->data;
$diseaseId = $data['diseaseId'];
unset($data['diseaseId']);
[$schema, $message] = $this->diseaseService->getSchemaField($diseaseId);
foreach ($data['data'] as $key => $value) {
$fieldSchema = collect($schema)->firstWhere('name', $key);
if (!$fieldSchema) {
throw new \Exception("Field '{$key}' is not defined in the schema.");
}
if ($fieldSchema['type'] === 'file') {
$isMultiple = $fieldSchema['multiple'] ?? false;
if ($isMultiple) {
$value = is_array($value) ? $value : [$value];
$fileUrls = [];
// Delete old files if they exist
if (isset($existingData[$key]) && is_array($existingData[$key])) {
foreach ($existingData[$key] as $oldFile) {
$this->fileStorage->deleteFile($oldFile, true);
}
}
// Store new files
foreach ($value as $index => $file) {
if ($file && is_file($file)) {
$fileUrls[] = $this->fileStorage->storeRecordFile(
$file,
$diseaseId,
$key . '-' . ($index + 1)
);
}
}
$existingData[$key] = $fileUrls;
} else {
// Single file handling
if (isset($existingData[$key])) {
// echo($existingData[$key]);
$this->fileStorage->deleteFile($existingData[$key], true);
}
if (is_file($value)) {
$existingData[$key] = $this->fileStorage->storeRecordFile(
$value,
$diseaseId,
$key
);
} else {
$existingData[$key] = null; // Clear the field if no new file is provided
}
}
} else {
// Non-file fields
$existingData[$key] = $value;
}
}
$diseaseRecord->update([
'data' => $existingData,
]);
DB::commit();
LogActionService::logAction(
$userId,
'edit',
'DiseaseRecord',
$diseaseRecord->id,
[
'old' => $oldData,
'new' => $diseaseRecord->toArray(),
'changed_fields' => array_keys($data['data'])
],
"Updated disease record ID: {$recordId}",
true
);
return [true, 'Disease record updated successfully.', $diseaseRecord->toArray()];
} catch (\Throwable $exception) {
DB::rollBack();
LogActionService::logAction(
$userId,
'edit',
'DiseaseRecord',
$recordId,
[
'attempted_changes' => array_keys($data['data']),
'error' => $exception->getMessage()
],
"Failed to update disease record: {$exception->getMessage()}",
false
);
return [false, 'Disease record update failed: ' . $exception->getMessage(), []];
}
}
public function deleteDiseaseRecord($recordId, $userId): array
{
try {
DB::beginTransaction();
$diseaseRecord = DiseaseRecord::find($recordId);
$diseaseId = $diseaseRecord->disease_id;
if (!$diseaseRecord) {
DB::rollBack();
LogActionService::logAction(
$userId,
'delete',
'Disease',
$recordId,
['error' => 'Disease Record not found'],
"Failed to delete disease record: Disease Record not found",
false
);
return [false, 'Disease Record not found.', []];
}
$recordInfo = [
'disease_id' => $diseaseId,
'data_fields' => array_keys($diseaseRecord->data),
'file_count' => collect($diseaseRecord->data)
->flatten()
->filter(function($value) {
return is_string($value) && file_exists(storage_path("app/public/{$value}"));
})
->count()
];
[$schema, $message] = $this->diseaseService->getSchemaField($diseaseId);
$recordData = $diseaseRecord->data;
$this->deleteRecordFiles($recordData, $schema);
$diseaseRecord->delete();
DB::commit();
LogActionService::logAction(
$userId,
'delete',
'DiseaseRecord',
$recordId,
$recordInfo,
"Deleted disease record ID: {$recordId}",
true
);
return [true, 'Disease record deleted successfully.', []];
} catch (\Throwable $exception) {
DB::rollBack();
LogActionService::logAction(
$userId,
'delete',
'DiseaseRecord',
$recordId,
['error' => $exception->getMessage()],
"Failed to delete disease record: {$exception->getMessage()}",
false
);
return [false, 'Disease record deletion failed: ' . $exception->getMessage(), []];
}
}
private function transformFileFields(array $data, array $schema): array
{
foreach ($schema as $field) {
// print_r($field);
if ($field['type'] === 'file' && isset($data[$field['name']])) {
// Handle single file
if (empty($field['multiple'])) {
$data[$field['name']] = $this->generatePublicFileUrl($data[$field['name']]);
} else {
// Handle multiple files
$data[$field['name']] = array_map(function ($filePath) {
return $this->generatePublicFileUrl($filePath);
}, $data[$field['name']]);
}
}
}
return $data;
}
/**
* Generate a public URL for a given file path.
*/
private function generatePublicFileUrl(string $filePath): string
{
return Storage::url('public/' . $filePath);
//return asset('storage/' . $filePath);
}
public function getDiseaseRecords($diseaseId, array $filters)
{
try {
[$schema, $message] = $this->diseaseService->getSchemaField($diseaseId);
$disease = Disease::findOrFail($diseaseId);
if (empty($schema)) {
if ($message === 'Access denied. This disease is private.'){
return [false, 'Cant Access Private Disease', []];
}
return [false, 'Schema not found for this disease.', []];
}
$query = $this->buildDiseaseRecordQuery($diseaseId, $filters);
$paginatedData = $this->paginateResults($query, $filters);
// Check if records exist and transform them
$records = !empty($paginatedData['records'])
? array_map(function ($record) use ($schema) {
$record['data'] = $this->transformFileFields($record['data'], $schema);
return $record;
}, $paginatedData['records'])
: [];
$response = [
'name' => $disease['name'],
'deskripsi' => $disease['deskripsi'],
'schema' => $schema,
'export_url' => $disease->export_url,
'records' => $records,
'pagination' => $paginatedData['pagination']
];
return [true, 'Disease records retrieved successfully.', $response];
} catch (\Throwable $exception) {
return [false, 'Failed to retrieve disease records: ' . $exception->getMessage(), []];
}
}
public function getDiseaseRecordDetails($diseaseId, $recordId): array
{
try {
[$schema, $message] = $this->diseaseService->getSchemaField($diseaseId);
if (empty($schema)) {
return [false, 'Schema not found for this disease.', []];
}
$record = DiseaseRecord::where('disease_id', $diseaseId)
->where('id', $recordId)
->firstOrFail();
// Transform file fields in the record
$record->data = $this->transformFileFields($record->data, $schema);
$response = [
'schema' => $schema,
'record' => $record->toArray(),
];
return [true, 'Disease record details retrieved successfully.', $response];
} catch (\Throwable $exception) {
return [false, 'Failed to retrieve disease record details: ' . $exception->getMessage(), []];
}
}
private function buildDiseaseRecordQuery(int $diseaseId, array $filters): Builder
{
$query = DiseaseRecord::where('disease_id', $diseaseId);
// $this->applyDiseaseRecordFilters($query, $filters);
if(!empty($filters['order_by'])){
if($filters['order_by'] === 'desc'){
$query->orderBy('created_at', 'desc');
}else if($filters['order_by'] === 'desc'){
$query->orderBy('created_at', 'asc');
}
}
$query->orderBy('updated_at', 'desc');
return $query;
}
private function paginateResults(Builder $query, array $filters): array
{
$perPage = isset($filters['per_page']) &&
is_numeric($filters['per_page']) &&
$filters['per_page'] > 0 &&
$filters['per_page'] <= self::MAX_PER_PAGE
? (int) $filters['per_page']
: self::DEFAULT_PER_PAGE;
$page = isset($filters['page']) &&
is_numeric($filters['page']) &&
$filters['page'] > 0
? (int) $filters['page']
: 1;
$results = $query->paginate($perPage, ['*'], 'page', $page);
if ($results->isEmpty() && $results->currentPage() > 1) {
$results = $query->paginate($perPage, ['*'], 'page', $results->lastPage());
}
return [
'records' => $results->items(),
'pagination' => [
'current_page' => $results->currentPage(),
'last_page' => $results->lastPage(),
'per_page' => (int) $results->perPage(),
'total' => $results->total(),
'from' => $results->firstItem(),
'to' => $results->lastItem(),
'has_more_pages' => $results->hasMorePages(),
]
];
}
private function isFileArray(array $value): bool
{
return count(array_filter($value, function ($item) {
return is_object($item) && method_exists($item, 'getClientOriginalExtension');
})) > 0;
}
public function deleteRecordFiles(array $data, array $schema): void
{
foreach ($data as $key => $value) {
$fieldSchema = collect($schema)->firstWhere('name', $key);
// Only proceed if this is a file field
if ($fieldSchema && $fieldSchema['type'] === 'file') {
if (is_array($value)) {
// Multiple files
foreach ($value as $filePath) {
$this->fileStorage->deleteFile($filePath, true);
}
} elseif (is_string($value)) {
// Single file
$this->fileStorage->deleteFile($value, true);
}
}
}
}
}