From 45cebcf3251a9d63aba813fd98621812e4895a61 Mon Sep 17 00:00:00 2001 From: Daeng Deni Mardaeni Date: Fri, 7 Nov 2025 10:57:46 +0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7(services):=20Selaraskan=20fallback?= =?UTF-8?q?=20path=20foto=20pada=20PreviewLaporanService=20dan=20tambah=20?= =?UTF-8?q?logging?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Menyelaraskan resolusi path file foto di PreviewLaporanService dengan logika fallback seperti pada komponen foto: - Menggunakan `originalPath = $path['path']` sebagai path utama - Jika `statusLpj == 1` dan file asli tidak ditemukan, maka: - Ekstrak dua bagian terakhir dari path (contoh: `251051/251051_2_2.png`) - Bangun `fallbackPath` dengan pola `surveyor/001/{lastTwoParts}` - Tentukan `pathToUse`: - Apabila `fallbackPath` ada dan file fallback ditemukan, gunakan `fallbackPath` - Jika tidak, tetap gunakan `originalPath` - Resolusi final: `storage_path('app/public/' . $pathToUse)` - Menambahkan logging untuk setiap operasi penting dan setiap titik pengembalian: - `Log::warning` saat path kosong terdeteksi dalam daftar paths - `Log::info` saat fallback kandidat dibangun dari `originalPath` - `Log::warning` saat file tidak ditemukan pada original maupun fallback (dengan menyertakan ketiganya: original, fallback, resolved) - `Log::info` saat file berhasil ditambahkan ke daftar unduhan - `Log::warning` saat tidak ada file valid setelah resolusi path - `Log::info` saat mengunduh single file - `Log::info` saat zip file berhasil dibuat (dengan jumlah file) - `Log::error` saat zip file gagal dibuat - Memindahkan logika resolusi path di dalam loop pengolahan `$paths` untuk setiap item: - Mengganti setting langsung `storage_path('app/public/' . $path['path'])` dengan resolusi path yang bisa fallback - Menjaga struktur kontrol dengan `continue` jika file final tetap tidak ditemukan - Menambahkan komentar level-fungsi (docblock) pada `previewLaporan`: - Menjelaskan tanggung jawab fungsi dalam menghasilkan PDF atau unduhan foto - Menjelaskan skenario fallback path dan tujuan mengurangi gambar hilang - Mendokumentasikan parameter dan bentuk nilai kembali respons --- app/Services/PreviewLaporanService.php | 134 ++++++++++++++++++------- 1 file changed, 98 insertions(+), 36 deletions(-) diff --git a/app/Services/PreviewLaporanService.php b/app/Services/PreviewLaporanService.php index e06b522..712f3eb 100644 --- a/app/Services/PreviewLaporanService.php +++ b/app/Services/PreviewLaporanService.php @@ -75,6 +75,20 @@ use Modules\Lpj\Http\Requests\FormSurveyorRequest; class PreviewLaporanService { + /** + * Preview Laporan dan unduh foto terkait dengan logika fallback path. + * + * Menghasilkan PDF atau paket unduhan foto berdasarkan status laporan. + * Jika file foto asli tidak ditemukan dan status LPJ adalah 1, maka + * sistem akan mencoba menggunakan fallback path dengan pola + * `surveyor/001/{lastTwoParts}` untuk meminimalisir gambar hilang. + * + * @param int $permohonan_id ID Permohonan + * @param int $dokumen_id ID Dokumen + * @param int $jaminan_id ID Jaminan + * @param string $back URL atau rute kembali + * @return \Symfony\Component\HttpFoundation\Response + */ public function previewLaporan($permohonan_id, $dokumen_id, $jaminan_id, $back) { $permohonan = $this->getPermohonanJaminanId( @@ -140,6 +154,8 @@ class PreviewLaporanService $tipeLaporanResponse = $this->checkPrintOutLaporan($permohonan_id, $document_id); $tipeLaporan = $tipeLaporanResponse->getData(); + //dd($permohonan_id, $document_id, $tipeLaporan); + if (!$tipeLaporan->status) { //return redirect()->back()->with('error', 'Laporan tidak valid'); } @@ -206,48 +222,91 @@ class PreviewLaporanService $mig_permohonan = json_decode($permohonan->mig_permohonan); if(($tipeLaporan->status === 'memo' && $permohonan->mig_permohonan) || $mig_permohonan->mig_mst_lpj_tot_nilai_pasar < 1){ - $paths = $formFoto['upload_foto'] ?? null; + $paths = $formFoto['upload_foto'] ?? null; - if (!is_array($paths) || empty($paths)) { - return response()->json(['error' => 'No files to download'], 404); - } - - $files = []; - foreach ($paths as $path) { - if (!$path['path']) { - continue; + if (!is_array($paths) || empty($paths)) { + return response()->json(['error' => 'No files to download'], 404); } - $fullPath = storage_path('app/public/' . $path['path']); - if (!file_exists($fullPath)) { - continue; + + $files = []; + foreach ($paths as $path) { + if (!$path['path']) { + Log::warning('PreviewLaporanService: Path kosong terdeteksi dalam daftar paths.'); + continue; + } + + // Logika fallback untuk path file + $originalPath = $path['path']; + $fallbackPath = null; + + // Jika file asli tidak ditemukan, buat fallback path + if ($statusLpj == 1) { + $fullOriginalPath = storage_path('app/public/' . $originalPath); + + if (!file_exists($fullOriginalPath)) { + // Ekstrak bagian akhir path (contoh: 251051/251051_2_2.png) + $pathParts = explode('/', $originalPath); + if (count($pathParts) >= 2) { + $lastTwoParts = array_slice($pathParts, -2); + $fallbackPath = 'surveyor/001/' . implode('/', $lastTwoParts); + Log::info('PreviewLaporanService: Menggunakan fallback path kandidat.', [ + 'original' => $originalPath, + 'fallback' => $fallbackPath, + ]); + } + } + } + + // Tentukan path yang akan digunakan + $pathToUse = ($fallbackPath && $statusLpj == 1 && file_exists(storage_path('app/public/' . $fallbackPath))) + ? $fallbackPath + : $originalPath; + + $fullPath = storage_path('app/public/' . $pathToUse); + if (!file_exists($fullPath)) { + Log::warning('PreviewLaporanService: File tidak ditemukan untuk original maupun fallback.', [ + 'original' => $originalPath, + 'fallback' => $fallbackPath, + 'resolved' => $pathToUse, + ]); + continue; + } + + Log::info('PreviewLaporanService: Menambahkan file untuk diunduh.', [ + 'resolved' => $pathToUse, + 'fullPath' => $fullPath, + ]); + $files[] = $fullPath; } - $files[] = $fullPath; - } - if (empty($files)) { - return response()->json(['error' => 'No valid files found'], 404); - } - - // For single file, download directly - if (count($files) === 1) { - return response()->download($files[0]); - } - - // For multiple files, create zip and download - $zipName = 'photos_' . time() . '.zip'; - $zipPath = storage_path('app/public/' . $zipName); - - $zip = new \ZipArchive(); - if ($zip->open($zipPath, \ZipArchive::CREATE) === true) { - foreach ($files as $file) { - $zip->addFile($file, basename($file)); + if (empty($files)) { + Log::warning('PreviewLaporanService: Tidak ada file valid ditemukan setelah resolusi path.'); + return response()->json(['error' => 'No valid files found'], 404); } - $zip->close(); - return response()->download($zipPath)->deleteFileAfterSend(true); - } - return response()->json(['error' => 'Failed to create zip file'], 500); - } + // For single file, download directly + if (count($files) === 1) { + Log::info('PreviewLaporanService: Mengunduh single file.', ['file' => $files[0]]); + return response()->download($files[0]); + } + + // For multiple files, create zip and download + $zipName = 'photos_' . time() . '.zip'; + $zipPath = storage_path('app/public/' . $zipName); + + $zip = new \ZipArchive(); + if ($zip->open($zipPath, \ZipArchive::CREATE) === true) { + foreach ($files as $file) { + $zip->addFile($file, basename($file)); + } + $zip->close(); + Log::info('PreviewLaporanService: Zip file berhasil dibuat.', ['zip' => $zipPath, 'count' => count($files)]); + return response()->download($zipPath)->deleteFileAfterSend(true); + } + + Log::error('PreviewLaporanService: Gagal membuat zip file.'); + return response()->json(['error' => 'Failed to create zip file'], 500); + } try { $pdf = $this->generatePDF($viewLaporan, compact( 'permohonan', @@ -280,6 +339,8 @@ class PreviewLaporanService private function generatePDF(string $viewLaporan, array $data) { + //return view('lpj::' . $viewLaporan, $data); + $pdf = PDF::loadView('lpj::' . $viewLaporan, $data); $pdf->setPaper('A4', 'portrait'); $pdf->set_option('isHtml5ParserEnabled', true); @@ -349,6 +410,7 @@ class PreviewLaporanService // Ambil data JSON dari statusLpj $data = json_decode($statusLpj->memo, true) ?? []; + $validationRules = [ 'memo' => [ 'kepada',