MIF_E31231042/app/Http/Controllers/LandingController.php

240 lines
8.0 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Biodata;
use App\Models\Ulasan;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use ZipArchive;
class LandingController extends Controller
{
public function index(Request $request)
{
$ulasan = Schema::hasTable('ulasans')
? Ulasan::where('is_hidden', false)->latest()->take(3)->get()
: collect();
$range = $request->query('range') === 'week' ? 'week' : 'month';
return view('landing', [
'ulasan' => $ulasan,
'diseaseNews' => $this->buildDiseaseNews($range),
]);
}
private function buildDiseaseNews(string $range): array
{
$startDate = $range === 'week'
? Carbon::now()->subDays(6)->startOfDay()
: Carbon::now()->subDays(29)->startOfDay();
$periodLabel = $range === 'week' ? '7 hari terakhir' : '30 hari terakhir';
if (!Schema::hasTable('biodata')) {
return $this->emptyDiseaseNews($range, $periodLabel, $startDate);
}
$diseaseStats = Biodata::query()
->select('hasil_diagnosis', DB::raw('COUNT(*) as total'))
->whereNotNull('hasil_diagnosis')
->where('hasil_diagnosis', '!=', '')
->where('created_at', '>=', $startDate)
->groupBy('hasil_diagnosis')
->orderByDesc('total')
->limit(3)
->get();
$topDisease = trim((string) ($diseaseStats->first()->hasil_diagnosis ?? ''));
$areaStats = collect();
$areaStatsByDisease = [];
if ($topDisease !== '') {
$areaStats = Biodata::query()
->where('hasil_diagnosis', $topDisease)
->where('created_at', '>=', $startDate)
->get(['alamat'])
->map(fn ($item) => $this->extractArea((string) ($item->alamat ?? '')))
->filter()
->countBy()
->sortDesc()
->take(6);
}
foreach ($diseaseStats as $row) {
$disease = trim((string) $row->hasil_diagnosis);
if ($disease === '') {
continue;
}
$areas = Biodata::query()
->where('hasil_diagnosis', $disease)
->where('created_at', '>=', $startDate)
->get(['alamat'])
->map(fn ($item) => $this->extractArea((string) ($item->alamat ?? '')))
->filter()
->countBy()
->sortDesc()
->take(6);
$areaStatsByDisease[$disease] = [
'labels' => $areas->keys()->values(),
'data' => $areas->values()->map(fn ($n) => (int) $n)->values(),
];
}
$knowledge = $this->getDiseaseKnowledge($topDisease);
return [
'range' => $range,
'period_label' => $periodLabel,
'start_label' => $this->formatDateLabel($startDate),
'end_label' => $this->formatDateLabel(Carbon::now()),
'top_disease' => $topDisease,
'total_cases' => (int) ($diseaseStats->first()->total ?? 0),
'disease_labels' => $diseaseStats->pluck('hasil_diagnosis')->map(fn ($name) => trim((string) $name))->values(),
'disease_data' => $diseaseStats->pluck('total')->map(fn ($n) => (int) $n)->values(),
'area_labels' => $areaStats->keys()->values(),
'area_data' => $areaStats->values()->map(fn ($n) => (int) $n)->values(),
'area_by_disease' => $areaStatsByDisease,
'handling' => $knowledge['pertolongan'] ?? [],
'prevention' => $knowledge['pencegahan'] ?? [],
];
}
private function emptyDiseaseNews(string $range, string $periodLabel, Carbon $startDate): array
{
return [
'range' => $range,
'period_label' => $periodLabel,
'start_label' => $this->formatDateLabel($startDate),
'end_label' => $this->formatDateLabel(Carbon::now()),
'top_disease' => '',
'total_cases' => 0,
'disease_labels' => collect(),
'disease_data' => collect(),
'area_labels' => collect(),
'area_data' => collect(),
'area_by_disease' => [],
'handling' => [],
'prevention' => [],
];
}
private function extractArea(string $address): string
{
$address = trim($address);
if ($address === '') {
return 'Tidak diketahui';
}
$parts = array_values(array_filter(array_map('trim', preg_split('/[,;-]+/', $address))));
$selected = $parts[0] ?? $address;
foreach ($parts as $part) {
if (preg_match('/\b(kota|kabupaten|kec\.?|kecamatan|kel\.?|kelurahan|desa)\b/i', $part)) {
$selected = $part;
break;
}
}
$selected = preg_replace('/\s+/', ' ', $selected);
return mb_convert_case($selected, MB_CASE_TITLE, 'UTF-8');
}
private function formatDateLabel(Carbon $date): string
{
$months = [
1 => 'Jan', 2 => 'Feb', 3 => 'Mar', 4 => 'Apr', 5 => 'Mei', 6 => 'Jun',
7 => 'Jul', 8 => 'Agu', 9 => 'Sep', 10 => 'Okt', 11 => 'Nov', 12 => 'Des',
];
return $date->format('d') . ' ' . $months[(int) $date->format('n')] . ' ' . $date->format('Y');
}
private function getDiseaseKnowledge(string $diseaseName): array
{
if ($diseaseName === '') {
return ['pertolongan' => [], 'pencegahan' => []];
}
$rows = $this->readXlsxRows(public_path('data/Bissmilah lagi.xlsx'));
foreach ($rows as $row) {
$name = trim((string) ($row['Penyakit'] ?? ''));
if (mb_strtolower($name) !== mb_strtolower($diseaseName)) {
continue;
}
return [
'pertolongan' => $this->splitRecommendation((string) ($row['Pertolongan'] ?? '')),
'pencegahan' => $this->splitRecommendation((string) ($row['Pencegahan'] ?? '')),
];
}
return ['pertolongan' => [], 'pencegahan' => []];
}
private function splitRecommendation(string $value): array
{
return array_values(array_filter(array_map('trim', explode(';', $value))));
}
private function readXlsxRows(string $path): array
{
if (!is_file($path) || !class_exists(ZipArchive::class)) {
return [];
}
$zip = new ZipArchive();
if ($zip->open($path) !== true) {
return [];
}
$sharedStrings = [];
$sharedXml = $zip->getFromName('xl/sharedStrings.xml');
if ($sharedXml !== false) {
$shared = simplexml_load_string($sharedXml);
foreach ($shared->si ?? [] as $item) {
$sharedStrings[] = trim((string) ($item->t ?? ''));
}
}
$sheetXml = $zip->getFromName('xl/worksheets/sheet1.xml');
$zip->close();
if ($sheetXml === false) {
return [];
}
$sheet = simplexml_load_string($sheetXml);
$rows = [];
foreach ($sheet->sheetData->row ?? [] as $xmlRow) {
$cells = [];
foreach ($xmlRow->c as $cell) {
$ref = (string) $cell['r'];
$column = preg_replace('/\d+/', '', $ref);
$value = (string) ($cell->v ?? '');
if ((string) $cell['t'] === 's') {
$value = $sharedStrings[(int) $value] ?? '';
}
$cells[$column] = trim($value);
}
$rows[] = $cells;
}
$headers = array_shift($rows) ?? [];
return array_values(array_filter(array_map(function ($row) use ($headers) {
$mapped = [];
foreach ($headers as $column => $header) {
if ($header !== '') {
$mapped[$header] = $row[$column] ?? '';
}
}
return $mapped;
}, $rows)));
}
}