defaultKabupatenId(); $initialFilters = $this->selectedFilters($request, $defaultKabupatenId); $payload = $this->dashboardPayload($initialFilters); $filterOptions = [ [ 'key' => 'kabupaten', 'label' => 'Kabupaten', 'options' => $this->kabupatenOptions(), 'icon' => 'tabler-map-pin', 'readonly' => true, ], [ 'key' => 'kecamatan', 'label' => 'Kecamatan', 'options' => $this->withAllOption('Semua Kecamatan', []), ], [ 'key' => 'desa', 'label' => 'Desa', 'options' => $this->withAllOption('Semua Desa', []), ], [ 'key' => 'komoditas', 'label' => 'Komoditas', 'options' => $this->withAllOption('Semua Komoditas', []), ], [ 'key' => 'segmentasi', 'label' => 'Segmentasi', 'options' => $this->withAllOption('Semua Segmentasi', []), ], ]; return view('dashboard.indikator-pertanian', [ 'title' => 'Indikator Pertanian', 'initialFilters' => $initialFilters, 'filterOptions' => $filterOptions, ] + $payload); } public function data(Request $request) { if ($request->query('mode') === 'filter-options') { return response()->json([ 'komoditas' => $this->komoditasOptions(), 'segmentasi' => $this->segmentasiOptions(), ]); } $filters = $this->selectedFilters($request, $this->defaultKabupatenId()); return response()->json([ 'filters' => $filters, ] + $this->dashboardPayload($filters)); } private function defaultKabupatenId(): string { $ngadaOption = collect($this->kabupatenOptions())->first( fn ($option) => str_contains(strtolower($option['label']), 'ngada') ); return $ngadaOption['value'] ?? 'all'; } private function dashboardPayload(array $filters): array { return [ 'summaryData' => $this->summaryData($filters), 'chartData' => $this->chartData($filters), ]; } private function summaryData(array $filters): array { $totalPetani = $this->applyPetaniFilters(Petani::query(), $filters)->count(); // $totalLuasLahan = ((float) $this->applyLahanFilters(Lahan::query(), $filters)->sum('luas_lahan')) / 10000; $totalLuasLahan = $this->applyLahanFilters(Lahan::has('petani'), $filters)->sum('luas_lahan'); $rataRataLuasLahan = $totalPetani > 0 ? $totalLuasLahan / $totalPetani : 0; $totalProduksiKg = $this->totalProduksiKg($filters); $rataRataProduksiKg = $totalPetani > 0 ? $totalProduksiKg / $totalPetani : 0; $rataRataProduktivitas = $totalLuasLahan > 0 ? $totalProduksiKg / $totalLuasLahan : 0; return [ [ 'value' => number_format($totalPetani, 0, ',', '.'), 'label' => 'Petani Terdata', 'description' => 'Total petani yang masuk sistem', 'icon' => 'tabler-users', 'variant' => 'primary', ], [ 'value' => number_format($totalLuasLahan, 2, ',', '.').' ha', 'label' => 'Total Luas Lahan', 'description' => 'Rata-rata '.number_format($rataRataLuasLahan, 2, ',', '.').' ha/petani', 'icon' => 'tabler-mountain', 'variant' => 'success', ], [ 'value' => number_format($totalProduksiKg, 0, ',', '.').' kg', 'label' => 'Total Produksi (Semua Komoditas)', 'description' => 'Rata-rata '.number_format($rataRataProduksiKg, 0, ',', '.').' kg/petani', 'icon' => 'tabler-wheat', 'variant' => 'warning', ], [ 'value' => number_format($rataRataProduktivitas, 0, ',', '.').' kg/ha', 'label' => 'Rata-rata Produktivitas', 'description' => 'Semua komoditas berdasarkan total produksi dan luas lahan', 'icon' => 'tabler-chart-bar', 'variant' => 'info', ], ]; } private function chartData(array $filters): array { return [ 'petaniPerKomoditas' => $this->petaniPerKomoditasChart($filters), 'luasLahanPerKecamatan' => $this->luasLahanPerKecamatanChart($filters), 'kondisiTanaman' => $this->kondisiTanamanChart($filters), 'statusKepemilikanLahan' => $this->statusKepemilikanLahanChart($filters), 'seranganHama' => $this->seranganHamaChart($filters), 'penyakitTanaman' => $this->penyakitTanamanChart($filters), 'keparahanSerangan' => $this->keparahanSeranganChart($filters), 'statusHakKelolaLahan' => $this->statusHakKelolaLahanChart($filters), 'praktikPemupukan' => $this->praktikPemupukanChart($filters), 'produksiPerKomoditas' => $this->produksiPerKomoditasChart($filters), 'produktivitasPerKomoditas' => $this->produktivitasPerKomoditasChart($filters), 'luasPanenPerKomoditas' => $this->luasPanenPerKomoditasChart($filters), 'statusPanen' => $this->statusPanenChart($filters), 'surveyProduktivitasHa' => $this->surveyProduktivitasByUnitChart($filters, 'ha_tahun'), 'surveyProduktivitasPohon' => $this->surveyProduktivitasByUnitChart($filters, 'pohon_tahun'), ]; } private function selectedFilters(Request $request, string $defaultKabupaten): array { $filters = [ 'kabupaten' => $defaultKabupaten, 'kecamatan' => $this->validFilterValue($request->query('kecamatan'), Kecamatan::class), 'desa' => $this->validFilterValue($request->query('desa'), DesaKelurahan::class), 'komoditas' => $this->validFilterValue($request->query('komoditas'), Komoditas::class), 'segmentasi' => $this->validSegmentasi((string) $request->query('segmentasi', 'all')), ]; if ($filters['desa'] !== 'all') { $desa = DesaKelurahan::query()->find($filters['desa']); if (! $desa || ($filters['kecamatan'] !== 'all' && (string) $desa->kecamatan_id !== $filters['kecamatan'])) { $filters['desa'] = 'all'; } } if ($filters['kecamatan'] === 'all') { $filters['desa'] = 'all'; } return $filters; } private function validFilterValue(mixed $value, string $modelClass): string { if (! $value || $value === 'all') { return 'all'; } return $modelClass::query()->whereKey($value)->exists() ? (string) $value : 'all'; } private function validSegmentasi(string $value): string { return in_array($value, [ 'Penggerak', 'Perintis', 'Pemerhati', 'Pemula', 'Belum tersegmentasi', 'all', ], true) ? $value : 'all'; } private function kabupatenOptions(): array { return $this->withAllOption( 'Semua Kabupaten', KabupatenKota::query() ->orderBy('nama') ->get(['id', 'kode', 'nama']) ->map(fn (KabupatenKota $kabupaten) => [ 'value' => (string) $kabupaten->id, 'label' => $this->kabupatenLabel($kabupaten), ]) ->values() ->all() ); } private function kecamatanOptions(): array { return $this->withAllOption( 'Semua Kecamatan', Kecamatan::query() ->orderBy('nama') ->get(['id', 'nama']) ->map(fn (Kecamatan $kecamatan) => [ 'value' => (string) $kecamatan->id, 'label' => $kecamatan->nama, ]) ->values() ->all() ); } private function desaOptions(): array { return $this->withAllOption( 'Semua Desa', DesaKelurahan::query() ->orderBy('nama') ->get(['id', 'nama', 'kecamatan_id']) ->map(fn (DesaKelurahan $desa) => [ 'value' => (string) $desa->id, 'label' => $desa->nama, 'parent' => (string) $desa->kecamatan_id, ]) ->values() ->all() ); } private function komoditasOptions(): array { return $this->withAllOption( 'Semua Komoditas', Komoditas::query() ->orderBy('nama') ->get(['id', 'nama']) ->map(fn (Komoditas $komoditas) => [ 'value' => (string) $komoditas->id, 'label' => $komoditas->nama, ]) ->values() ->all() ); } private function segmentasiOptions(): array { $segments = SkorPetani::query() ->whereNotNull('skor_kesiapan_adopsi') ->pluck('skor_kesiapan_adopsi') ->map(fn ($score) => $this->segmentLabel((float) $score)) ->filter() ->unique() ->sortBy(fn ($segment) => array_search($segment, [ 'Penggerak', 'Perintis', 'Pemerhati', 'Pemula', 'Belum tersegmentasi', ], true)) ->map(fn ($segment) => [ 'value' => $segment, 'label' => $segment, ]) ->values() ->all(); return $this->withAllOption('Semua Segmentasi', $segments); } private function totalProduksiKg(array $filters): float { return $this->applyProduksiFilters(Produksi::query(), $filters) ->whereNotNull('jumlah_panen') ->get(['jumlah_panen', 'satuan']) ->sum(fn (Produksi $produksi) => $this->toKilograms( (float) $produksi->jumlah_panen, (string) $produksi->satuan )); } private function petaniPerKomoditasChart(array $filters): array { $rows = $this->applyPetaniFilters(Petani::query(), $filters) ->leftJoin('master_komoditas as k', 'k.id', '=', 'petani.komoditas_id') ->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label") ->selectRaw('COUNT(petani.id) as total') ->groupBy('k.id', 'k.nama') ->orderByDesc('total') ->get(); return [ 'labels' => $rows->pluck('label')->values()->all(), 'series' => $rows->pluck('total')->map(fn ($value) => (int) $value)->values()->all(), ]; } private function luasLahanPerKecamatanChart(array $filters): array { $rows = $this->applyLahanFilters(Lahan::query(), $filters) ->leftJoin('master_desa_kelurahan as d', 'd.id', '=', 'map_lahan.desa_kelurahan_id') ->leftJoin('master_kecamatan as k', 'k.id', '=', 'd.kecamatan_id') ->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label") ->selectRaw('SUM(map_lahan.luas_lahan) / 10000 as total') ->groupBy('k.id', 'k.nama') ->havingRaw('SUM(map_lahan.luas_lahan) > 0') ->orderByDesc('total') ->limit(8) ->get() ->filter(fn ($row) => round((float) $row->total, 2) > 0) ->values(); return [ 'labels' => $rows->pluck('label')->values()->all(), 'series' => $rows->pluck('total')->map(fn ($value) => round((float) $value, 2))->values()->all(), ]; } private function kondisiTanamanChart(array $filters): array { $rows = $this->applyTanamanTableFilters(DB::table('map_tanaman'), $filters) ->whereNull('map_tanaman.deleted_at') ->whereNotNull('map_tanaman.kondisi_tanaman') ->selectRaw('map_tanaman.kondisi_tanaman as label') ->selectRaw('COUNT(map_tanaman.id) as total') ->groupBy('map_tanaman.kondisi_tanaman') ->orderByDesc('total') ->get(); if ($rows->isEmpty()) { $rows = $this->applyLahanFilters(Lahan::query(), $filters) ->whereNull('deleted_at') ->whereNotNull('kondisi_tanaman') ->selectRaw('kondisi_tanaman as label') ->selectRaw('COUNT(map_lahan.id) as total') ->groupBy('kondisi_tanaman') ->orderByDesc('total') ->get(); } return [ 'labels' => $rows->pluck('label')->map(fn ($label) => $this->shortEnumLabel((string) $label))->values()->all(), 'series' => $rows->pluck('total')->map(fn ($value) => (int) $value)->values()->all(), ]; } private function seranganHamaChart(array $filters): array { return $this->tanamanAttributeChart( $filters, 'serangan_hama', fn ($label) => $this->enumLabel(SeranganHama::class, (string) $label) ); } private function penyakitTanamanChart(array $filters): array { return $this->tanamanAttributeChart( $filters, 'penyakit_tanaman', fn ($label) => $this->enumLabel(PenyakitTanaman::class, (string) $label) ); } private function keparahanSeranganChart(array $filters): array { return $this->tanamanAttributeChart( $filters, 'keparahan_serangan', fn ($label) => $this->keparahanSeranganLabel((string) $label) ); } private function statusKepemilikanLahanChart(array $filters): array { $rows = $this->applyLahanFilters(Lahan::query(), $filters) ->whereNotNull('status_kepemilikan') ->selectRaw('status_kepemilikan as label') ->selectRaw('COUNT(map_lahan.id) as total') ->groupBy('status_kepemilikan') ->orderByDesc('total') ->get(); return $this->chartFromRows($rows, fn ($label) => $this->shortEnumLabel((string) $label)); } private function statusHakKelolaLahanChart(array $filters): array { $rows = $this->applySosialEkonomiFilters(SosialEkonomi::query(), $filters) ->whereNotNull('status_kepemilikan_lahan') ->selectRaw('status_kepemilikan_lahan as label') ->selectRaw('COUNT(sosial_ekonomi.id) as total') ->groupBy('status_kepemilikan_lahan') ->orderByDesc('total') ->get(); return $this->chartFromRows( $rows, fn ($label) => $this->enumLabel(StatusKepemilikanLahanSosialEkonomi::class, (string) $label) ); } private function praktikPemupukanChart(array $filters): array { $rows = $this->applyPraktikBudidayaFilters(PraktikBudidaya::query(), $filters) ->whereNotNull('pemberian_pupuk') ->selectRaw('pemberian_pupuk as label') ->selectRaw('COUNT(praktik_budidaya.id) as total') ->groupBy('pemberian_pupuk') ->orderBy('pemberian_pupuk') ->get(); return $this->chartFromRows( $rows, fn ($label) => $this->pemberianPupukLabel((int) $label) ); } private function produksiPerKomoditasChart(array $filters): array { $rows = $this->applyProduksiFilters(Produksi::query(), $filters) ->leftJoin('master_komoditas as k', 'k.id', '=', 'produksi.komoditas_id') ->whereNotNull('jumlah_panen') ->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label") ->selectRaw('produksi.jumlah_panen') ->selectRaw('produksi.satuan') ->get() ->groupBy('label') ->map(fn ($items) => round($items->sum( fn (Produksi $produksi) => $this->toKilograms( (float) $produksi->jumlah_panen, (string) $produksi->satuan ) ), 2)) ->filter(fn ($total) => $total > 0) ->sortDesc(); return [ 'labels' => $rows->keys()->values()->all(), 'series' => $rows->values()->map(fn ($value) => round((float) $value, 2))->values()->all(), ]; } private function produktivitasPerKomoditasChart(array $filters): array { $rows = $this->applyProduksiFilters(Produksi::query(), $filters) ->leftJoin('master_komoditas as k', 'k.id', '=', 'produksi.komoditas_id') ->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label") ->selectRaw('produksi.jumlah_panen') ->selectRaw('produksi.satuan') ->selectRaw('produksi.luas_panen') ->selectRaw('produksi.produktivitas') ->get() ->groupBy('label') ->map(function ($items) { $storedAverage = $items ->pluck('produktivitas') ->filter(fn ($value) => (float) $value > 0) ->avg(); if ($storedAverage > 0) { return round((float) $storedAverage, 2); } $totalProduksiKg = $items->sum( fn (Produksi $produksi) => $this->toKilograms( (float) $produksi->jumlah_panen, (string) $produksi->satuan ) ); $totalLuasPanen = $items->sum(fn (Produksi $produksi) => (float) $produksi->luas_panen); return $totalLuasPanen > 0 ? round($totalProduksiKg / $totalLuasPanen, 2) : 0; }) ->filter(fn ($total) => $total > 0) ->sortDesc(); return [ 'labels' => $rows->keys()->values()->all(), 'series' => $rows->values()->map(fn ($value) => round((float) $value, 2))->values()->all(), ]; } private function luasPanenPerKomoditasChart(array $filters): array { $rows = $this->applyProduksiFilters(Produksi::query(), $filters) ->leftJoin('master_komoditas as k', 'k.id', '=', 'produksi.komoditas_id') ->whereNotNull('luas_panen') ->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label") ->selectRaw('SUM(produksi.luas_panen) as total') ->groupBy('k.id', 'k.nama') ->havingRaw('SUM(produksi.luas_panen) > 0') ->orderByDesc('total') ->get(); return [ 'labels' => $rows->pluck('label')->values()->all(), 'series' => $rows->pluck('total')->map(fn ($value) => round((float) $value, 2))->values()->all(), ]; } private function statusPanenChart(array $filters): array { $rows = $this->applyProduksiFilters(Produksi::query(), $filters) ->whereNotNull('status_panen') ->selectRaw("COALESCE(status_panen, 'Belum ditentukan') as label") ->selectRaw('COUNT(produksi.id) as total') ->groupBy('status_panen') ->orderByDesc('total') ->get(); return $this->chartFromRows($rows, fn ($label) => $this->shortEnumLabel((string) $label)); } private function surveyProduktivitasByUnitChart(array $filters, string $unit): array { $rows = $this->applySurveyProduktivitasFilters(SurveyProduktivitas::query(), $filters) ->leftJoin('master_komoditas as k', 'k.id', '=', 'survey_produktivitas.komoditas_id') ->where('satuan', $unit) ->whereNotNull('kuantitas') ->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label") ->selectRaw('AVG(survey_produktivitas.kuantitas) as total') ->groupBy('k.id', 'k.nama') ->havingRaw('AVG(survey_produktivitas.kuantitas) > 0') ->orderByDesc('total') ->get(); return [ 'labels' => $rows->pluck('label')->values()->all(), 'series' => $rows->pluck('total')->map(fn ($value) => round((float) $value, 2))->values()->all(), ]; } private function chartFromRows($rows, callable $labelResolver): array { return [ 'labels' => $rows ->pluck('label') ->map(fn ($label) => $labelResolver($label)) ->values() ->all(), 'series' => $rows ->pluck('total') ->map(fn ($value) => (int) $value) ->values() ->all(), ]; } private function tanamanAttributeChart(array $filters, string $field, callable $labelResolver): array { $qualifiedField = 'map_tanaman.'.$field; $rows = $this->applyTanamanTableFilters(DB::table('map_tanaman'), $filters) ->whereNull('map_tanaman.deleted_at') ->whereNotNull($qualifiedField) ->selectRaw($qualifiedField.' as label') ->selectRaw('COUNT(map_tanaman.id) as total') ->groupBy($qualifiedField) ->orderByDesc('total') ->get(); if ($rows->isEmpty()) { $rows = $this->applyLahanFilters(Lahan::query(), $filters) ->whereNotNull($field) ->selectRaw($field.' as label') ->selectRaw('COUNT(map_lahan.id) as total') ->groupBy($field) ->orderByDesc('total') ->get(); } return $this->chartFromRows($rows, $labelResolver); } private function applyPetaniFilters($query, array $filters) { return $query ->when($filters['kecamatan'] !== 'all', function ($query) use ($filters) { $query->whereHas('desaKelurahan', fn ($desa) => $desa->where('kecamatan_id', $filters['kecamatan'])); }) ->when($filters['desa'] !== 'all', fn ($query) => $query->where('desa_kelurahan_id', $filters['desa'])) ->when($filters['komoditas'] !== 'all', fn ($query) => $query->where('komoditas_id', $filters['komoditas'])) ->when($filters['segmentasi'] !== 'all', function ($query) use ($filters) { $query->whereHas('skor', function ($skor) use ($filters) { $this->applySegmentasiRange($skor, $filters['segmentasi']); }); }); } private function applyLahanFilters($query, array $filters) { return $query ->when($filters['kecamatan'] !== 'all', function ($query) use ($filters) { $query->whereHas('desaKelurahan', fn ($desa) => $desa->where('kecamatan_id', $filters['kecamatan'])); }) ->when($filters['desa'] !== 'all', fn ($query) => $query->where('desa_kelurahan_id', $filters['desa'])) ->when($filters['komoditas'] !== 'all', fn ($query) => $query->where('komoditas_id', $filters['komoditas'])) ->when($filters['segmentasi'] !== 'all', function ($query) use ($filters) { $query->whereIn('petani_id', $this->segmentasiPetaniIdsQuery($filters['segmentasi'])); }); } private function applyProduksiFilters($query, array $filters) { return $query ->when($filters['kecamatan'] !== 'all' || $filters['desa'] !== 'all' || $filters['segmentasi'] !== 'all', function ($query) use ($filters) { $query->whereHas('lahan', function ($lahan) use ($filters) { $this->applyLahanFilters($lahan, $filters); }); }) ->when($filters['komoditas'] !== 'all', fn ($query) => $query->where('komoditas_id', $filters['komoditas'])); } private function applySosialEkonomiFilters($query, array $filters) { return $query->whereHas('petani', function ($petani) use ($filters) { $this->applyPetaniFilters($petani, $filters); }); } private function applyPraktikBudidayaFilters($query, array $filters) { return $query->whereHas('petani', function ($petani) use ($filters) { $this->applyPetaniFilters($petani, $filters); }); } private function applySurveyProduktivitasFilters($query, array $filters) { return $query ->whereHas('petani', function ($petani) use ($filters) { $this->applyPetaniFilters($petani, $filters); }) ->when($filters['komoditas'] !== 'all', fn ($query) => $query->where('komoditas_id', $filters['komoditas'])); } private function applyTanamanTableFilters($query, array $filters) { return $query ->leftJoin('map_lahan as l', 'l.id', '=', 'map_tanaman.lahan_id') ->when($filters['kecamatan'] !== 'all', function ($query) use ($filters) { $query ->leftJoin('master_desa_kelurahan as d', 'd.id', '=', 'l.desa_kelurahan_id') ->where('d.kecamatan_id', $filters['kecamatan']); }) ->when($filters['desa'] !== 'all', fn ($query) => $query->where('l.desa_kelurahan_id', $filters['desa'])) ->when($filters['komoditas'] !== 'all', fn ($query) => $query->where('map_tanaman.komoditas_id', $filters['komoditas'])) ->when($filters['segmentasi'] !== 'all', function ($query) use ($filters) { $query->where(function ($query) use ($filters) { $query ->whereIn('map_tanaman.petani_id', $this->segmentasiPetaniIdsQuery($filters['segmentasi'])) ->orWhereIn('l.petani_id', $this->segmentasiPetaniIdsQuery($filters['segmentasi'])); }); }); } private function segmentasiPetaniIdsQuery(string $segmentasi) { return Petani::query() ->select('id') ->whereHas('skor', function ($skor) use ($segmentasi) { $this->applySegmentasiRange($skor, $segmentasi); }); } private function applySegmentasiRange($query, string $segmentasi) { return match ($segmentasi) { 'Penggerak' => $query->where('skor_kesiapan_adopsi', '>=', 4), 'Perintis' => $query->where('skor_kesiapan_adopsi', '>=', 3)->where('skor_kesiapan_adopsi', '<', 4), 'Pemerhati' => $query->where('skor_kesiapan_adopsi', '>=', 2)->where('skor_kesiapan_adopsi', '<', 3), 'Pemula' => $query->where('skor_kesiapan_adopsi', '>=', 1)->where('skor_kesiapan_adopsi', '<', 2), default => $query->where(function ($query) { $query->whereNull('skor_kesiapan_adopsi')->orWhere('skor_kesiapan_adopsi', '<', 1); }), }; } private function shortEnumLabel(string $value): string { return str($value) ->replace('_', ' ') ->headline() ->toString(); } private function enumLabel(string $enumClass, int|string $value): string { $case = $enumClass::tryFrom($value); if (! $case) { return $this->shortEnumLabel((string) $value); } return method_exists($case, 'label') ? $case->label() : $this->shortEnumLabel((string) $case->value); } private function keparahanSeranganLabel(string $value): string { return match (KeparahanSerangan::tryFrom($value)) { KeparahanSerangan::RINGAN => 'Ringan', KeparahanSerangan::SEDANG => 'Sedang', KeparahanSerangan::BERAT => 'Parah', default => $this->shortEnumLabel($value), }; } private function pemberianPupukLabel(int $value): string { return match (PemberianPupuk::tryFrom($value)) { PemberianPupuk::TIDAK_PERNAH => 'Tidak pernah', PemberianPupuk::JENIS_DOSIS_WAKTU_TIDAK_MENENTU => 'Tidak menentu', PemberianPupuk::JENIS_SESUAI_DOSIS_TIDAK_MENENTU => 'Jenis sesuai', PemberianPupuk::JENIS_DOSIS_SESUAI_WAKTU_CUKUP_TEPAT => 'Cukup tepat', PemberianPupuk::JENIS_DOSIS_SESUAI_WAKTU_TEPAT => 'Tepat & rutin', default => $this->shortEnumLabel((string) $value), }; } private function toKilograms(float $value, string $unit): float { return match (strtolower($unit)) { 'ton' => $value * 1000, 'kuintal', 'kwintal' => $value * 100, default => $value, }; } private function withAllOption(string $label, array $options): array { return array_merge([ [ 'value' => 'all', 'label' => $label, ], ], $options); } private function kabupatenLabel(KabupatenKota $kabupaten): string { return preg_replace('/^(kabupaten|kota)\s+/i', '', $kabupaten->nama); } private function segmentLabel(float $score): string { return match (true) { $score >= 4.0 => 'Penggerak', $score >= 3.0 => 'Perintis', $score >= 2.0 => 'Pemerhati', $score >= 1.0 => 'Pemula', default => 'Belum tersegmentasi', }; } }