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

415 lines
14 KiB
PHP

<?php
namespace App\Services;
use App\Models\Disease;
use App\Http\Requests\CreateDiseaseRequest;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use App\Services\LogActionService;
use Illuminate\Support\Facades\Storage;
class DiseaseService
{
private const DEFAULT_PER_PAGE = 10;
private const MAX_PER_PAGE = 100;
protected $fileStorage;
public function __construct(
FileStorageService $fileStorage)
{
$this->fileStorage = $fileStorage;
}
public function createDisease(array $data, $userId): array
{
try {
DB::beginTransaction();
$image_url = null;
if (isset($data['cover_page']) && $data['cover_page']) {
$disease = Disease::create([
'name' => $data['name'],
'deskripsi' => $data['deskripsi'],
'visibilitas' => $data['visibilitas'],
'schema' => $data['schema'],
'cover_page' => null,
]);
$image_url = $this->fileStorage->storeCoverImage($data['cover_page'], $disease->id);
$disease->update(['cover_page' => $image_url]);
} else {
$disease = Disease::create([
'name' => $data['name'],
'deskripsi' => $data['deskripsi'],
'visibilitas' => $data['visibilitas'],
'schema' => $data['schema'],
'cover_page' => null,
]);
}
DB::commit();
LogActionService::logAction(
$userId,
'create',
'Disease',
$disease->id,
$disease->toArray(),
"Created disease: {$disease->name}",
true
);
return [true, 'Disease created successfully.', $disease->toArray()];
} catch (\Throwable $exception) {
DB::rollBack();
LogActionService::logAction(
$userId,
'create',
'Disease',
null,
[
'name' => $data['name'] ?? null,
'error' => $exception->getMessage()
],
"Failed to create disease: {$exception->getMessage()}",
false
);
return [false, 'Disease creation failed: ' . $exception->getMessage(), []];
}
}
public function editDisease($id, array $data, $userId): array
{
try {
// var_dump($data);
DB::beginTransaction();
$disease = Disease::find($id);
if (!$disease) {
DB::rollBack();
LogActionService::logAction(
$userId,
'edit',
'Disease',
$id,
['error' => 'Disease not found'],
"Failed to edit disease: Disease not found",
false
);
return [false, 'Disease not found.', []];
}
$oldData = $disease->toArray();
if (isset($data['cover_page']) && $data['cover_page']) {
if ($disease->cover_page) {
$this->fileStorage->deleteFile($disease->cover_page, true);
}
$data['cover_page'] = $this->fileStorage->storeCoverImage($data['cover_page'], $disease->id);
} else {
unset($data['cover_page']);
}
$changedFields = array_keys(array_diff_assoc($data, $oldData));
// Get only the values that are actually changing
$relevantOldData = array_intersect_key($oldData, $data);
$relevantNewData = array_intersect_key($data, $oldData);
$disease->update($data);
DB::commit();
LogActionService::logAction(
$userId,
'edit',
'Disease',
$disease->id,
[
'old' => $relevantOldData,
'new' => $relevantNewData,
'changed_fields' => $changedFields
],
"Updated disease: {$disease->name}",
true
);
return [true, 'Disease updated successfully.', $disease];
} catch (\Throwable $exception) {
DB::rollBack();
LogActionService::logAction(
$userId,
'edit',
'Disease',
$id,
[
'attempted_changes' => array_keys($data),
'error' => $exception->getMessage()
],
"Failed to update disease: {$exception->getMessage()}",
false
);
return [false, 'Disease update failed: ' . $exception->getMessage(), []];
}
}
public function deleteDisease($id, $userId): array
{
try {
DB::beginTransaction();
$disease = Disease::find($id);
if (!$disease) {
DB::rollBack();
LogActionService::logAction(
$userId,
'delete',
'Disease',
$id,
['error' => 'Disease not found'],
"Failed to delete disease: Disease not found",
false
);
return [false, 'Disease not found.', []];
}
$diseaseInfo = [
'name' => $disease->name,
'had_cover_page' => !is_null($disease->cover_page),
'schema_columns_count' => count($disease->schema['columns'] ?? [])
];
if ($disease->cover_page) {
$this->fileStorage->deleteFile($disease->cover_page, true);
}
$directoryPath = "diseases/records/$id";
$this->fileStorage->deleteDirectory($directoryPath, true);
$disease->delete();
DB::commit();
LogActionService::logAction(
$userId,
'delete',
'Disease',
$id,
$diseaseInfo,
"Deleted disease: {$disease->name}",
true
);
return [true, 'Disease deleted successfully.', []];
} catch (\Throwable $exception) {
DB::rollBack();
LogActionService::logAction(
$userId,
'delete',
'Disease',
$id,
['error' => $exception->getMessage()],
"Failed to delete disease: {$exception->getMessage()}",
false
);
return [false, 'Disease deletion failed: ' . $exception->getMessage(), []];
}
}
public function getDisease(array $filters, $user): array
{
try {
$query = Disease::query();
$query->withCount('diseaseRecords');
if ($user->role === 'operator') {
$query->where('id', $user->disease_id);
} elseif ($user->role === 'peneliti') {
$query->where('visibilitas', 'publik');
}
$this->applyDiseaseFilters($query, $filters);
$paginatedData = $this->paginateResults($query, $filters, 'diseases');
return [true, 'Diseases retrieved successfully.', $paginatedData];
} catch (\Throwable $exception) {
return [false, 'Failed to retrieve diseases: ' . $exception->getMessage(), []];
}
}
public function getDiseaseDetails($id): array
{
try {
$user = auth()->user();
$disease = Disease::withCount('diseaseRecords')->findOrFail($id);
if (!$disease) {
return [false, 'Disease not found.', []];
}
// Admins can access all diseases
if ($user->role === 'admin') {
return [true, 'Disease details retrieved successfully.', $disease];
}
// Operators can only access their assigned diseases
if ($user->role === 'operator') {
$managesDisease = $user->managed_diseases['disease_id'];
if ($managesDisease != $id) {
return [false, 'Access denied. You are not assigned to this disease.', []];
}
}
// Researchers can only access public diseases
if ($user->role === 'peneliti') {
if ($user->approval_status !== 'approved') {
return [false, 'Access denied. Your account is not approved.', []];
}
if ($disease->visibilitas !== 'publik') {
return [false, 'Access denied. This disease is private.', []];
}
}
return [true, 'Disease details retrieved successfully.', $disease];
} catch (\Throwable $exception) {
return [false, 'Failed to retrieve disease details: ' . $exception->getMessage(), []];
}
}
public function getStatistics(array $filters): array
{
try {
$query = Disease::query();
$query->withCount('diseaseRecords');
$this->applyDiseaseFilters($query, $filters);
$diseases = $query->get(['id', 'name', 'disease_records_count']);
$totalDiseaseRecords = $diseases->sum('disease_records_count');
$stats = [
'total_disease_records' => $totalDiseaseRecords,
'diseases' => $diseases->map(function ($disease) {
return [
'id' => $disease->id,
'name' => $disease->name,
'disease_records_count' => $disease->disease_records_count,
];
}),
];
return [true, 'Disease statistics retrieved successfully.', $stats];
} catch (\Throwable $exception) {
return [false, 'Failed to retrieve statistics: ' . $exception->getMessage(), []];
}
}
public function getSchemaField(int $diseaseId): array
{
try {
[$success, $message, $disease] = $this->getDiseaseDetails($diseaseId);
if (!$success) {
return [[], $message];
}
$schema = $disease->schema['columns'] ?? null;
if (!$schema) {
return [[], $message];
}
$formattedSchema = [];
foreach ($schema as $column) {
$field = [
'name' => $column['name'] ?? null,
'type' => $column['type'] ?? null,
];
if ($field['type'] === 'file') {
$field['format'] = $column['format'];
$field['multiple'] = isset($column['multiple']) ? (bool) $column['multiple'] : false; // Ensure multiple is set with default false
}
$field['is_visible'] = filter_var($column['is_visible'] ?? false, FILTER_VALIDATE_BOOLEAN);
$formattedSchema[] = $field;
}
return [$formattedSchema, 'Schema Retrieved Successfully'];
} catch (\Throwable $exception) {
return [];
}
}
private function applyDiseaseFilters(Builder $query, array $filters): void
{
if (!empty($filters['visibilitas'])) {
$query->where('visibilitas', $filters['visibilitas']);
}
if (!empty($filters['name'])) {
$query->where('name', 'ILIKE', '%' . trim($filters['name']) . '%');
}
if (!empty($filters['column_type'])) {
$query->whereJsonContains('schema->columns', ['type' => $filters['column_type']]);
}
if (!empty($filters['column_name'])) {
$query->whereJsonContains('schema->columns', ['name' => $filters['column_name']]);
}
//Sorting
$query->orderBy('updated_at', 'desc');
}
private function paginateResults(Builder $query, array $filters, string $itemsKey): 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 [
$itemsKey => $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(),
]
];
}
}