$sessionData, 'alternatifs_by_komponen' => $alternatifsByKomponen, 'waktu_makan_id' => $waktuMakanId ]); return redirect()->route('alternatif.pilih') ->with('error', 'Data session tidak lengkap. Silakan pilih alternatif terlebih dahulu.'); } // Ambil semua kriteria $kriterias = Kriteria::all(); $bobotKriteria = $this->getBobotKriteria($kriterias); // Proses untuk setiap komponen foreach ($alternatifsByKomponen as $komponenId => $komponenData) { $alternatifs = $komponenData['alternatifs']; // Log untuk debugging \Log::info('Memproses komponen:', [ 'komponen_id' => $komponenId, 'jumlah_alternatif' => count($alternatifs) ]); // Inisialisasi matriks perbandingan $matriksPerbandingan = []; foreach ($kriterias as $kriteria) { $matriksPerbandingan[$kriteria->id] = []; foreach ($alternatifs as $alt1) { $matriksPerbandingan[$kriteria->id][$alt1['id']] = []; foreach ($alternatifs as $alt2) { // Menggunakan nilai yang sudah dinormalisasi dari session $nilai1 = $alt1[strtolower($kriteria->nama) . '_normalized'] ?? 0; $nilai2 = $alt2[strtolower($kriteria->nama) . '_normalized'] ?? 0; if ($nilai2 == 0) { $matriksPerbandingan[$kriteria->id][$alt1['id']][$alt2['id']] = 0; } else { $matriksPerbandingan[$kriteria->id][$alt1['id']][$alt2['id']] = $nilai1 / $nilai2; } } } } // Hitung prioritas lokal untuk setiap kriteria $prioritasLokal = []; foreach ($kriterias as $kriteria) { $prioritasLokal[$kriteria->id] = []; // Hitung jumlah kolom $jumlahKolom = []; foreach ($alternatifs as $alt2) { $jumlahKolom[$alt2['id']] = 0; foreach ($alternatifs as $alt1) { $jumlahKolom[$alt2['id']] += $matriksPerbandingan[$kriteria->id][$alt1['id']][$alt2['id']]; } } // Normalisasi matriks $matriksNormal = []; foreach ($alternatifs as $alt1) { $matriksNormal[$alt1['id']] = []; foreach ($alternatifs as $alt2) { if ($jumlahKolom[$alt2['id']] > 0) { $matriksNormal[$alt1['id']][$alt2['id']] = $matriksPerbandingan[$kriteria->id][$alt1['id']][$alt2['id']] / $jumlahKolom[$alt2['id']]; } else { $matriksNormal[$alt1['id']][$alt2['id']] = 0; } } } // Hitung prioritas lokal (rata-rata baris) foreach ($alternatifs as $alt) { $jumlahBaris = array_sum($matriksNormal[$alt['id']]); $prioritasLokal[$kriteria->id][$alt['id']] = $jumlahBaris / count($alternatifs); } // Simpan skor ke database foreach ($alternatifs as $alt) { SkorMakanan::updateOrCreate( [ 'makanan_id' => $alt['id'], 'kriteria_id' => $kriteria->id, 'waktu_makan_id' => $waktuMakanId, 'komponen_id' => $komponenId ], ['nilai' => $prioritasLokal[$kriteria->id][$alt['id']]] ); } } // Hitung skor akhir foreach ($alternatifs as $alt) { $skorAkhir = 0; foreach ($kriterias as $kriteria) { $skorAkhir += $prioritasLokal[$kriteria->id][$alt['id']] * $bobotKriteria[$kriteria->id]; } // Simpan rekomendasi Rekomendasi::updateOrCreate( [ 'makanan_id' => $alt['id'], 'komponen_id' => $komponenId, 'waktu_makan_id' => $waktuMakanId, 'user_id' => Auth::id(), 'tanggal_rekomendasi' => $sessionData['tanggal_rekomendasi'] ], ['nilai_akhir' => $skorAkhir] ); } } return redirect()->route('rekomendasi.index') ->with('success', 'Perhitungan AHP berhasil dilakukan.'); } catch (\Exception $e) { \Log::error('Error in hitungDanSimpanOtomatis:', [ 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString(), 'session_data' => session()->all() ]); return redirect()->back() ->with('error', 'Terjadi kesalahan saat melakukan perhitungan: ' . $e->getMessage()); } } private function getBobotKriteria($kriterias) { try { $waktuMakanId = session('waktu_makan_id'); if (!$waktuMakanId) { throw new \Exception('Waktu makan ID tidak ditemukan di session'); } $bobotKriteria = []; foreach ($kriterias as $kriteria) { $bobot = BobotKriteria::where([ 'kriteria_id' => $kriteria->id, 'waktu_makan_id' => $waktuMakanId ])->first(); if (!$bobot) { // Jika tidak ada bobot, coba ambil dari perbandingan kriteria $perbandinganKriteria = PerbandinganKriteria::where([ 'kriteria_id_1' => $kriteria->id, 'waktu_makan_id' => $waktuMakanId ])->first(); if ($perbandinganKriteria) { $total = PerbandinganKriteria::where([ 'kriteria_id_1' => $kriteria->id, 'waktu_makan_id' => $waktuMakanId ])->sum('nilai'); $bobotKriteria[$kriteria->id] = $total > 0 ? $perbandinganKriteria->nilai / $total : 0; } else { \Log::warning("Bobot kriteria tidak ditemukan untuk kriteria {$kriteria->nama} pada waktu makan ID: {$waktuMakanId}"); $bobotKriteria[$kriteria->id] = 0; } } else { $bobotKriteria[$kriteria->id] = $bobot->bobot; } } // Normalisasi bobot kriteria $totalBobot = array_sum($bobotKriteria); if ($totalBobot > 0) { foreach ($bobotKriteria as $key => $value) { $bobotKriteria[$key] = $value / $totalBobot; } } // Log untuk debugging \Log::info('Bobot kriteria yang diambil:', [ 'waktu_makan_id' => $waktuMakanId, 'bobot' => $bobotKriteria ]); return $bobotKriteria; } catch (\Exception $e) { \Log::error('Error in getBobotKriteria: ' . $e->getMessage()); throw $e; } } public function tampilHasil() { try { // Ambil data dari session $hasilRekomendasi = session('hasil_rekomendasi'); if (!$hasilRekomendasi) { return redirect()->route('alternatif.pilih') ->with('error', 'Data rekomendasi tidak ditemukan.'); } // Ambil data yang diperlukan dengan select spesifik $kriterias = Kriteria::select('id', 'nama')->get(); $komponens = Komponen::select('id', 'nama')->get(); $waktuMakan = WaktuMakan::select('id', 'nama')->findOrFail($hasilRekomendasi['waktu_makan_id']); // Inisialisasi array untuk menyimpan hasil per komponen $hasilPerKomponen = []; // Proses setiap komponen foreach ($komponens as $komponen) { // Ambil rekomendasi untuk komponen ini $rekomendasis = Rekomendasi::with('makanan') ->where('waktu_makan_id', $hasilRekomendasi['waktu_makan_id']) ->where('komponen_id', $komponen->id) ->orderByDesc('nilai_akhir') ->get(); if ($rekomendasis->isNotEmpty()) { // Ambil detail skor hanya untuk makanan yang ada di rekomendasi $detailSkor = []; foreach ($rekomendasis as $rekomendasi) { $detailSkor[$rekomendasi->makanan_id] = []; foreach ($kriterias as $kriteria) { $skor = SkorMakanan::select('nilai') ->where('makanan_id', $rekomendasi->makanan_id) ->where('kriteria_id', $kriteria->id) ->first(); $detailSkor[$rekomendasi->makanan_id][$kriteria->nama] = $skor ? $skor->nilai : 0; } } // Simpan hasil untuk komponen ini $hasilPerKomponen[$komponen->id] = [ 'komponen' => $komponen, 'rekomendasis' => $rekomendasis, 'detailSkor' => $detailSkor ]; } } // Ambil bobot kriteria $bobotKriteria = []; foreach ($kriterias as $kriteria) { $bobot = BobotKriteria::select('bobot') ->where('kriteria_id', $kriteria->id) ->first(); $bobotKriteria[$kriteria->id] = $bobot ? $bobot->bobot : 0; } // Normalisasi bobot $totalBobot = array_sum($bobotKriteria); if ($totalBobot > 0) { foreach ($bobotKriteria as $key => $value) { $bobotKriteria[$key] = $value / $totalBobot; } } // Set CR to null since it's temporarily disabled $consistencyRatio = null; return view('admin.rekomendasi', compact( 'hasilPerKomponen', 'kriterias', 'waktuMakan', 'consistencyRatio', 'bobotKriteria' )); } catch (\Exception $e) { \Log::error('Error in tampilHasil:', [ 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return redirect()->route('alternatif.pilih') ->with('error', 'Terjadi kesalahan saat menampilkan hasil: ' . $e->getMessage()); } } private function hitungConsistencyRatio() { $waktuMakanId = session('waktu_makan_id'); if (!$waktuMakanId) { return 0; // Return 0 if no waktu_makan_id in session } $perbandinganKriterias = PerbandinganKriteria::where('waktu_makan_id', $waktuMakanId)->get(); $n = Kriteria::count(); if ($perbandinganKriterias->isEmpty()) { return 0; // Return 0 if no perbandingan data } // Buat matriks perbandingan $matrix = array_fill(0, $n, array_fill(0, $n, 1)); foreach ($perbandinganKriterias as $perbandingan) { $matrix[$perbandingan->kriteria_id_1 - 1][$perbandingan->kriteria_id_2 - 1] = $perbandingan->nilai; $matrix[$perbandingan->kriteria_id_2 - 1][$perbandingan->kriteria_id_1 - 1] = 1 / $perbandingan->nilai; } // Hitung eigenvalue maksimum $rowSums = array_map(function($row) { return array_sum($row); }, $matrix); $totalSum = array_sum($rowSums); $normalizedMatrix = array_map(function($row) use ($totalSum) { return array_map(function($val) use ($totalSum) { return $val / $totalSum; }, $row); }, $matrix); $eigenvalue = 0; for ($i = 0; $i < $n; $i++) { $sum = 0; for ($j = 0; $j < $n; $j++) { $sum += $matrix[$i][$j] * array_sum($normalizedMatrix[$j]); } $eigenvalue += $sum / array_sum($normalizedMatrix[$i]); } $eigenvalue /= $n; // Random Index values for n = 1 to 10 $RI = [0, 0, 0.58, 0.90, 1.12, 1.24, 1.32, 1.41, 1.45, 1.49]; // Hitung Consistency Index $CI = ($eigenvalue - $n) / ($n - 1); // Hitung Consistency Ratio return $n <= 2 ? 0 : $CI / $RI[$n - 1]; } private function getNilaiKriteria($makanan, $kriteria) { switch (strtolower($kriteria->nama)) { case 'energi': return is_array($makanan) ? $makanan['energi'] : $makanan->energi; case 'protein': return is_array($makanan) ? $makanan['protein'] : $makanan->protein; case 'lemak': return is_array($makanan) ? $makanan['lemak'] : $makanan->lemak; case 'karbohidrat': return is_array($makanan) ? $makanan['karbohidrat'] : $makanan->karbohidrat; case 'natrium': return is_array($makanan) ? $makanan['natrium'] : $makanan->natrium; default: return 0; } } private function isCostCriteria($kriteriaNama) { return in_array(strtolower($kriteriaNama), ['lemak', 'natrium']); } private function normalisasiNilai($nilai, $kriteria, $makanans) { // Kumpulkan semua nilai untuk kriteria ini $nilaiKriteria = []; foreach ($makanans as $makanan) { $nilaiKriteria[] = $this->getNilaiKriteria($makanan, $kriteria); } // Cek jenis kriteria (benefit atau cost) if ($this->isCostCriteria($kriteria->nama)) { // Untuk kriteria cost (lemak dan natrium), nilai lebih kecil lebih baik $nilaiInverse = $nilai > 0 ? 1 / $nilai : 0; $totalInverse = 0; foreach ($nilaiKriteria as $n) { $totalInverse += ($n > 0 ? 1 / $n : 0); } return $totalInverse > 0 ? $nilaiInverse / $totalInverse : 0; } else { // Untuk kriteria benefit (energi dan karbohidrat), nilai lebih besar lebih baik $total = array_sum($nilaiKriteria); return $total > 0 ? $nilai / $total : 0; } } public function index() { $waktuMakans = WaktuMakan::with(['komponens', 'consistencyRatios' => function($query) { $query->where('user_id', Auth::id()) ->latest('tanggal_perhitungan'); }]) ->select('waktu_makans.*') ->selectRaw('( SELECT COUNT(*) > 0 FROM rekomendasis r WHERE r.waktu_makan_id = waktu_makans.id AND r.user_id = ? ) as has_recommendation', [Auth::id()]) ->selectRaw('( SELECT MAX(tanggal_rekomendasi) FROM rekomendasis r WHERE r.waktu_makan_id = waktu_makans.id AND r.user_id = ? ) as latest_calculation', [Auth::id()]) ->get(); return view('admin.rekomendasi-list', compact('waktuMakans')); } public function detail($waktuMakanId) { try { $waktuMakan = WaktuMakan::findOrFail($waktuMakanId); // Ambil rekomendasi terbaru untuk waktu makan ini $latestRekomendasi = Rekomendasi::where('waktu_makan_id', $waktuMakanId) ->where('user_id', Auth::id()) ->orderBy('tanggal_rekomendasi', 'desc') ->first(); if (!$latestRekomendasi) { return redirect()->route('rekomendasi.index') ->with('error', 'Belum ada rekomendasi untuk waktu makan ini.'); } // Set data untuk tampilan detail $hasilRekomendasi = [ 'tanggal_rekomendasi' => $latestRekomendasi->tanggal_rekomendasi, 'waktu_makan_id' => $waktuMakanId ]; // Ambil semua kriteria $kriterias = Kriteria::all(); // Ambil bobot kriteria dari database $bobotKriteria = []; foreach ($kriterias as $kriteria) { $bobot = BobotKriteria::where('kriteria_id', $kriteria->id)->first(); $bobotKriteria[$kriteria->id] = $bobot ? $bobot->bobot : 0; } // Normalisasi bobot $totalBobot = array_sum($bobotKriteria); if ($totalBobot > 0) { foreach ($bobotKriteria as $key => $value) { $bobotKriteria[$key] = $value / $totalBobot; } } // Ambil komponen yang memiliki rekomendasi $komponens = Komponen::whereExists(function ($query) use ($waktuMakanId, $latestRekomendasi) { $query->select(DB::raw(1)) ->from('rekomendasis') ->whereColumn('rekomendasis.komponen_id', 'komponens.id') ->where('rekomendasis.waktu_makan_id', $waktuMakanId) ->where('rekomendasis.tanggal_rekomendasi', $latestRekomendasi->tanggal_rekomendasi); })->get(); $hasilPerKomponen = []; foreach ($komponens as $komponen) { // Ambil rekomendasi untuk komponen ini dengan eager loading $rekomendasis = Rekomendasi::with(['makanan' => function($query) { $query->select('makanans.id', 'makanans.nama', 'makanans.energi', 'makanans.lemak', 'makanans.karbohidrat', 'makanans.natrium'); }]) ->where('waktu_makan_id', $waktuMakanId) ->where('komponen_id', $komponen->id) ->where('user_id', Auth::id()) ->where('tanggal_rekomendasi', $latestRekomendasi->tanggal_rekomendasi) ->orderByDesc('nilai_akhir') ->get(); // Ambil detail skor untuk setiap makanan $detailSkor = []; foreach ($rekomendasis as $rekomendasi) { $detailSkor[$rekomendasi->makanan_id] = []; foreach ($kriterias as $kriteria) { $skor = SkorMakanan::where('makanan_id', $rekomendasi->makanan_id) ->where('kriteria_id', $kriteria->id) ->where('waktu_makan_id', $waktuMakanId) ->where('komponen_id', $komponen->id) ->first(); $detailSkor[$rekomendasi->makanan_id][$kriteria->nama] = $skor ? $skor->nilai : 0; } // Ambil data perbandingan untuk makanan ini $perbandinganData = PerbandinganAlternatif::where('waktu_makan_id', $waktuMakanId) ->where('komponen_id', $komponen->id) ->where(function($query) use ($rekomendasi) { $query->where('alternatif_id_1', $rekomendasi->makanan_id) ->orWhere('alternatif_id_2', $rekomendasi->makanan_id); }) ->get(); if ($perbandinganData->isNotEmpty()) { $detailSkor[$rekomendasi->makanan_id]['perbandingan'] = $perbandinganData; } } $hasilPerKomponen[$komponen->id] = [ 'komponen' => $komponen, 'rekomendasis' => $rekomendasis, 'detailSkor' => $detailSkor ]; } // Ambil CR terbaru dari ConsistencyRatioCriteria untuk waktu makan ini $latestCR = ConsistencyRatioCriteria::where('waktu_makan_id', $waktuMakanId) ->latest() ->first(); return view('admin.rekomendasi', compact( 'waktuMakan', 'hasilRekomendasi', 'kriterias', 'bobotKriteria', 'hasilPerKomponen', 'latestCR' )); } catch (\Exception $e) { return redirect()->route('rekomendasi.index') ->with('error', 'Terjadi kesalahan saat menampilkan detail: ' . $e->getMessage()); } } }